如果趕時間,直接看最后一部分怜森。
還是老規(guī)矩:為了避免歧義我還是要先列下我的環(huán)境
$ uname -a
Linux debian9-64-Desktop 4.9.0-8-amd64 #1 SMP Debian 4.9.110-3+deb9u6 (2018-10-08) x86_64 GNU/Linux
$ gcc --version
gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
需求:
寫個模板類仍律,有個自增唯一ID
這里只是給了一個思路,也是我在工作過程中使用到的低零。
需要建立一個 ReqSession.h
"C++模板類的成員函數(shù)定義與聲明必須在一個頭文件中"
#ifndef REQSESSION_H
#define REQSESSION_H
#include <stdint.h>
#include <iostream>
//自增的參數(shù)
static uint32_t m_sessionId =0 ;
//模板類
template <typename T>
class ReqSessionTMP
{
public:
ReqSessionTMP(T* data){
++m_sessionId;
m_data =data;
}
void printSession(){
std::cout<<"模板類:id:"<<m_sessionId<<",param:"<<m_data<<std::endl;
delete m_data; // 這里做了釋放的操作
}
private:
//攜帶的參數(shù)
T * m_data =nullptr;
};
#endif // REQSESSION_H
如果發(fā)現(xiàn)修改模板類的頭文件沒有用處婆翔,則需要增加預(yù)編譯參數(shù) **-MMD**
在我的工程項(xiàng)目里面就是加到 *.pro 文件, QMAKE_CXXFLAGS += -MMD
開始調(diào)用:
void UA4Qml2::createReqSession(const QString str)
{
//創(chuàng)建一個會話
//基本數(shù)據(jù)類型
//const char* conver to char* 掏婶,const char* 強(qiáng)轉(zhuǎn)char*
std::string tmpStr = str.toStdString();
char* c_str=new char[tmpStr.length()]; //注意這里的內(nèi)存釋放
memcpy(c_str,tmpStr.c_str(),tmpStr.length());
ReqSessionTMP<char> session(c_str) ;
session.printSession();
}
看下打印
模板類:id:1,param:hello session
模板類:id:2,param:hello session
看到這里也許有人問啃奴,這里為啥要用模板類,用個void* 不就可以了嗎雄妥?
我們再繼續(xù)實(shí)踐最蕾,增加普通類,和上面的 ReqSessionTMP
放在同一個文件里( PS :c++就是不一樣依溯,一個文件可以放多個不同類的聲明,想我java好像不行)
//普通類
class ReqSession
{
public:
ReqSession(void* data){
++m_sessionId;
m_data =data;
}
void printSession(){
std::cout<<"普通類:id:"<<m_sessionId<<",param:"<<m_data<<std::endl;
delete m_data;// 這里做了釋放的操作瘟则,注意這里沒有強(qiáng)轉(zhuǎn)
}
private:
//攜帶的參數(shù)
void * m_data =nullptr;
};
事實(shí)證明黎炉,使用剛才的方式進(jìn)行打印,其實(shí)是沒有區(qū)別的醋拧。
我們現(xiàn)在改成復(fù)雜一點(diǎn)的例子慷嗜。我們再新建一個普通類,用于會話傳輸?shù)膬?nèi)容
#include <stdint.h>
#include <iostream>
class Session{
public:
char * name =nullptr;
uint32_t age =0;
~Session(){
std::cout<<"~Session"<<std::endl;
}
};
讓我們來看下兩種不同的調(diào)用
void UA4Qml2::createReqSession(const QString str)
{
//復(fù)雜數(shù)據(jù)類型
std::string tmpStr = str.toStdString();
char* c_str=new char[tmpStr.length()];
memcpy(c_str,tmpStr.c_str(),tmpStr.length());
Session* session =new Session();
session->name = c_str;
#if 0
ReqSession reqSession(session) ;
//可以看到丹壕,沒有調(diào)用析構(gòu)函數(shù)
reqSession.printSession();
#else
ReqSessionTMP<Session> reqSession(session) ;
//可以看到調(diào)用了析構(gòu)函數(shù)
reqSession.printSession();
#endif
}
看下輸出的結(jié)果:
# 使用模板類
模板類:id:1,param:0x556faa8f7f20
~Session
模板類:id:2,param:0x556faa3c62a0
~Session
# 使用普通類
普通類:id:1,param:0x563bfec51f50
普通類:id:2,param:0x563bfe7055d0
好像有點(diǎn)偏題啊庆械。而且 本著哪里申請哪里釋放的原則,這里不應(yīng)該在模板類里面進(jìn)行 釋放內(nèi)存的操作菌赖,這是有問題的干奢。所以,如果把delete的相關(guān)代碼刪除盏袄,則兩邊效果是一致的忿峻,當(dāng)然,需要在外部進(jìn)行釋放內(nèi)存咯辕羽。
來逛尚,在說:上面這樣寫的就沒有問題嗎?
這是一個隱藏的很深的bug刁愿〈履【這是我今天特別想說的點(diǎn)】
如果有很多個不同的模板類,被打到了不同的庫里面會怎樣铣口?(什么意思滤钱?就是說我有很多個不同的特例模板類,然后打成不同的庫脑题,這個時候就有問題了)
當(dāng)然是件缸,static
關(guān)鍵字不生效了。啥叫不生效了叔遂,就是在同一個so里面的 static
還是唯一的他炊,但是和別的庫就會是一樣的Id,導(dǎo)致程序出現(xiàn)異常已艰。
來給出最終的方案痊末,因?yàn)榘裺tatic關(guān)鍵字放在了頭文件的緣故,所以導(dǎo)致上面的問題×ú簦現(xiàn)在改下凿叠,直接上代碼
采用繼承的方案
新建一個 basereqsession.h
basereqsession.cpp
#include <stdint.h>
class BaseReqSession
{
public:
BaseReqSession();
static uint32_t& get_session_id();
};
#include "basereqsession.h"
BaseReqSession::BaseReqSession()
{}
static uint32_t m_session_id = 0; //在cpp里面進(jìn)行定義
uint32_t &BaseReqSession::get_session_id() //返回值類型必須是引用
{
return m_session_id;
}
然后模板類只要繼承即可
#include "basereqsession.h"
template <typename T>
class ReqSessionTMP :BaseReqSession //這里用繼承
{
public:
ReqSessionTMP(T* data){
++get_session_id();
m_data =data;
}
private:
//攜帶的參數(shù)
T * m_data =nullptr;
};
最后完善一下:之前的代碼
#ifndef REQSESSION_H
#define REQSESSION_H
#include <stdint.h>
#include <iostream>
#include "basereqsession.h"
template <typename T>
class ReqSessionTMP :BaseReqSession
{
public:
ReqSessionTMP(T* data){
autoIncreateSessionId();
m_data =data;
}
int getSessionId()
{
return get_session_id();
}
private:
void autoIncreateSessionId()
{
++get_session_id();
if(get_session_id() == 0)
{
get_session_id() = 1;
}
}
private:
//攜帶的參數(shù)
T * m_data =nullptr;
};
#endif // REQSESSION_H