午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

MFC六大關(guān)鍵技術(shù)之運(yùn)行時(shí)類型識(shí)別

 jtll521 2010-10-30
運(yùn)行時(shí)類型識(shí)別(RTTI)即是程序執(zhí)行過(guò)程中知道某個(gè)對(duì)象屬于某個(gè)類,我們平時(shí)用C++編程接觸的RTTI一般是編譯器的RTTI,即是在新版本的VC++編譯器里面選用“使能RTTI”,然后載入typeinfo.h文件,就可以使用一個(gè)叫typeid()的運(yùn)算子,它的地位與在C++編程中的sizeof()運(yùn)算子類似的地方(包含一個(gè)頭文件,然后就有一個(gè)熟悉好用的函數(shù))。typdid()關(guān)鍵的地方是可以接受兩個(gè)類型的參數(shù):一個(gè)是類名稱,一個(gè)是對(duì)象指針。所以我們判別一個(gè)對(duì)象是否屬于某個(gè)類就可以象下面那樣:

if (typeid (ClassName)== typeid(*ObjectName)){
((ClassName*)ObjectName)->Fun();
}
  象上面所說(shuō)的那樣,一個(gè)typeid()運(yùn)算子就可以輕松地識(shí)別一個(gè)對(duì)象是否屬于某一個(gè)類,但MFC并不是用typeid()的運(yùn)算子來(lái)進(jìn)行動(dòng)態(tài)類型識(shí)別,而是用一大堆令人費(fèi)解的宏。很多學(xué)員在這里很疑惑,好象MFC在大部分地方都是故作神秘。使們大家編程時(shí)很迷惘,只知道在這里加入一組宏,又在那兒加入一個(gè)映射,而不知道我們?yōu)槭裁匆尤脒@些東東。

  其實(shí),早期的MFC并沒(méi)有typeid()運(yùn)算子,所以只能沿用一個(gè)老辦法。我們甚至可以想象一下,如果MFC早期就有template(模板)的概念,可能更容易解決RTTI問(wèn)題。

  所以,我們要回到“古老”的年代,想象一下,要完成RTTI要做些什么事情。就好像我們?cè)谝粋€(gè)新型(新型到我們還不認(rèn)識(shí))電器公司里面,我們要識(shí)別哪個(gè)是電飯鍋,哪個(gè)是電磁爐等等,我們要查看登記的各電器一系列的信息,我們才可以比較、鑒別,那個(gè)個(gè)東西是什么!
要登記一系列的消息并不是一件簡(jiǎn)單的事情,大家可能首先想到用數(shù)組登記對(duì)象。但如果用數(shù)組,我們要定義多大的數(shù)組才好呢,大了浪費(fèi)空間,小了更加不行。所以我們要用另一種數(shù)據(jù)結(jié)構(gòu)——鏈表。因?yàn)殒湵砝碚撋峡纱罂尚。梢詿o(wú)限擴(kuò)展。

  鏈表是一種常用的數(shù)據(jù)結(jié)構(gòu),簡(jiǎn)單地說(shuō),它是在一個(gè)對(duì)象里面保存了指向下一個(gè)同類型對(duì)象的指針。我們大體可以這樣設(shè)計(jì)我們的類: 

struct CRuntimeClass
{
……類的名稱等一切信息……
CRuntimeClass * m_pNextClass;//指向鏈表中下一CRuntimeClass對(duì)象的指針
};
  鏈表還應(yīng)該有一個(gè)表頭和一個(gè)表尾,這樣我們?cè)诓殒湵碇懈鲗?duì)象元素的信息的時(shí)候才知道從哪里查起,到哪兒結(jié)束。我們還要注明本身是由哪能個(gè)類派生。所以我們的鏈表類要這樣設(shè)計(jì):

struct CRuntimeClass
{
……類的名稱等一切信息……
CRuntimeClass * m_pBaseClass;//指向所屬的基類。
CRuntimeClass * m_pNextClass;//定義表尾的時(shí)候只要定義此指針為空就可以 了。
static CRuntimeClass* pFirstClass;//這里表頭指針屬于靜態(tài)變量,因?yàn)槲覀冎纒tatic變量在內(nèi)存中只初始化一次,就可以為各對(duì)象所用!保證了各對(duì)象只有一個(gè)表頭。
};
  有了CRuntimeClass結(jié)構(gòu)后,我們就可以定義鏈表了:

static CRuntimeClass classCObject={NULL,NULL};//這里定義了一個(gè)CRuntimeClass對(duì)象,
  因?yàn)閏lassCObject無(wú)基類,所以m_pBaseClass為NULL。因?yàn)槟壳爸挥幸粋€(gè)元素(即目前沒(méi)有下一元素),所以m_pNextClass為NULL(表尾)。

  至于pFirstClass(表頭),大家可能有點(diǎn)想不通,它到什么地方去了。因?yàn)槲覀冞@里并不想把classCObject作為鏈表表頭,我們還要在前面插入很多的CRuntimeClass對(duì)象,并且因?yàn)閜FirstClass為static指針,即是說(shuō)它不是屬于某個(gè)對(duì)象,所以我們?cè)谟盟耙瘸跏蓟?br>
CRuntimeClass* CRuntimeClass::pFirstClass=NULL;
  現(xiàn)在我們可以在前面插入一個(gè)CRuntimeClass對(duì)象,插入之前我得重要申明一下:如果單純?yōu)榱诉\(yùn)行時(shí)類型識(shí)別,我們未必用到m_pNextClass指針(更多是在運(yùn)行時(shí)創(chuàng)建時(shí)用),我們關(guān)心的是類本身和它的基類。這樣,查找一個(gè)對(duì)象是否屬于一個(gè)類時(shí),主要關(guān)心的是類本身及它的基類:

CRuntimeClass classCCmdTarget={ &classCObject, NULL};
CRuntimeClass classCWnd={ &classCCmdTarget ,NULL };
CRuntimeClass classCView={ &classCWnd , NULL };
  好了,上面只是僅僅為一個(gè)指針m_pBaseClass賦值(MFC中真正CRuntimeClass有多個(gè)成員變量和方法),就連接成了鏈表。假設(shè)我們現(xiàn)在已全部構(gòu)造完成自己需要的CRuntimeClass對(duì)象,那么,這時(shí)候應(yīng)該定義表頭。即要用pFirstClass指針指向我們最后構(gòu)造的CRuntimeClass對(duì)象——classCView。

CRuntimeClass::pFirstClass=&classCView;
  現(xiàn)在鏈表有了,表頭表尾都完善了,問(wèn)題又出現(xiàn)了,我們應(yīng)該怎樣訪問(wèn)每一個(gè)CRuntimeClass對(duì)象?要判斷一個(gè)對(duì)象屬于某類,我們要從表頭開(kāi)始,一直向表尾查找到表尾,然后才能比較得出結(jié)果嗎。肯定不是這樣! 

  大家可以這樣想一下,我們構(gòu)造這個(gè)鏈表的目的,就是構(gòu)造完之后,能夠按主觀地拿一個(gè)CRuntimeClass對(duì)象和鏈表中的元素作比較,看看其中一個(gè)對(duì)象中否屬于你指定的類。這樣,我們需要有一個(gè)函數(shù),一個(gè)能返回自身類型名的函數(shù)GetRuntimeClass()。

  上面簡(jiǎn)單地說(shuō)一下鏈表的過(guò)程,但單純有這個(gè)鏈表是沒(méi)有任何意義。回到MFC中來(lái),我們要實(shí)現(xiàn)的是在每個(gè)需要有RTTI能力的類中構(gòu)造一個(gè)CRuntimeClass對(duì)象,比較一個(gè)類是否屬于某個(gè)對(duì)象的時(shí)候,實(shí)際上只是比較CRuntimeClass對(duì)象。

  如何在各個(gè)類之中插入CRuntimeClass對(duì)象,并且指定CRuntimeClass對(duì)象的內(nèi)容及CRuntimeClass對(duì)象的鏈接,這里起碼有十行的代碼才能完成。在每個(gè)需要有RTTI能力的類設(shè)計(jì)中都要重復(fù)那十多行代碼是一件乏味的事情,也容易出錯(cuò),所以MFC用了兩個(gè)宏代替這些工作,即DECLARE_DYNAMIC(類名)和IMPLEMENT_DYNAMIC(類名,基類名)。從這兩個(gè)宏我們可以看出在MFC名類中的CRuntimeClass對(duì)象構(gòu)造連接只有類名及基類名的不同!

  到此,可能會(huì)有朋友問(wèn):為什么要用兩個(gè)宏,用一個(gè)宏不可以代換CRuntimeClass對(duì)象構(gòu)造連接嗎?個(gè)人認(rèn)為肯定可以,因?yàn)楹曛皇俏淖执鷵Q的游戲而已。但我們?cè)诰幊讨校^文件與源文件是分開(kāi)的,我們要在頭文件頭聲明變量及方法,在源文件里實(shí)具體實(shí)現(xiàn)。即是說(shuō)我們要在頭文件中聲明: 

public:
static CRuntimeClass classXXX //XXX為類名
virtual CRuntime* GetRuntimeClass() const;
  然后在源文件里實(shí)現(xiàn):

CRuntimeClass* XXX::classXXX={……};
CRuntime* GetRuntimeClass() const;
{ return &XXX:: classXXX;}//這里不能直接返回&classXXX,因?yàn)閟tatic變量是類擁有而不是對(duì)象擁有。
  我們一眼可以看出MFC中的DECLARE_DYNAMIC(類名)宏應(yīng)該這樣定義:

#define DECLARE_DYNAMIC(class_name) public: static CRuntimeClass class##class_name;
virtual CRuntimeClass* GetRuntimeClass() const;
  其中##為連接符,可以讓我們傳入的類名前面加上class,否則跟原類同名,大家會(huì)知道產(chǎn)生什么后果。

  有了上面的DECLARE_DYNAMIC(類名)宏之后,我們?cè)陬^文件里寫(xiě)上一句:

DECLARE_DYNAMIC(XXX)
  宏展開(kāi)后就有了我們想要的:

public:
static CRuntimeClass classXXX //XXX為類名
virtual CRuntime* GetRuntimeClass() const;
  對(duì)于IMPLEMENT_DYNAMIC(類名,基類名),看來(lái)也不值得在這里代換文字了,大家知道它是知道回事,宏展開(kāi)后為我們做了什么,再深究真是一點(diǎn)意義都沒(méi)有! 

  有了此鏈表之后,就像有了一張存放各類型的網(wǎng),我們可以輕而易舉地RTTI。CObject有一個(gè)函數(shù)BOOL IsKindOf(const CRuntimeClass* pClass) const;,被它以下所有派生員繼承。

  此函數(shù)實(shí)現(xiàn)如下:

BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
CRuntimeClass* pClassThis=GetRuntimeClass();//獲得自己的CRuntimeClass對(duì)象指針。
while(pClassThis!=NULL)
{
if(pClassThis==pClass) return TRUE;
pClassThis=pClassThis->m_pBaseClass;//這句最關(guān)鍵,指向自己基類,再回頭比較,一直到盡頭m_pBaseClass為NULL結(jié)束。
}
return FALSE;
}
  說(shuō)到這里,運(yùn)行時(shí)類型識(shí)別(RTTI)算是完成了。寫(xiě)這篇文章的時(shí)候,我一直重感冒。我曾一度在想,究竟寫(xiě)這東西是為了什么。因?yàn)槿绻野堰@些時(shí)間用在別的地方(甚至幫別人打打字),應(yīng)該有數(shù)百元的報(bào)酬。

  是什么讓“嗜財(cái)如命”的我繼續(xù)寫(xiě)下去?我想,無(wú)非是想交幾個(gè)計(jì)算機(jī)的朋友而已。計(jì)算機(jī)是大家公認(rèn)高科技的東西,但學(xué)習(xí)它的朋友大多只能默默無(wú)聞,外界的朋友也不知道怎么去認(rèn)識(shí)你。程序員更不是“潮流”的東西,更加得不到別人的認(rèn)可。

  有一件個(gè)人認(rèn)為很典型的事情,有一天,我跟一個(gè)朋友到一個(gè)單位里面。里面有一個(gè)女打字員。朋友看著她熟練的指法,心悅誠(chéng)服地說(shuō):“她的電腦水平比你的又高了一個(gè)很高的層次!”,那個(gè)女的打字高手亦自豪地說(shuō):“我靠電腦為生,電腦水平肯定比你(指筆者)的好一點(diǎn)!換著是你,如果以電腦為生,我也不敢說(shuō)好過(guò)你!”。雖然我想聲明我是計(jì)算機(jī)專業(yè)的,但我知道沒(méi)有理解,所以我只得客氣地點(diǎn)頭。 

  選擇電腦“潮流”的東西實(shí)際是選擇了平凡,而選擇做程序員就是選擇了孤獨(dú)!幸好我不是一個(gè)專門(mén)的程序員,但即使如此,我愿意做你們的朋友,因?yàn)槲覑?ài)你們!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多