小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

技術(shù)資料-【MFC六大關(guān)鍵技術(shù)剖析之動(dòng)態(tài)創(chuàng)建】

 xiakezcf 2005-10-11
MFC六大關(guān)鍵技術(shù)剖析之動(dòng)態(tài)創(chuàng)建
  動(dòng)態(tài)創(chuàng)建就是運(yùn)行時(shí)創(chuàng)建指定類(lèi)的對(duì)象,在MFC中大量使用。如框架窗口對(duì)象、視對(duì)象,還有文檔對(duì)象都需要由文檔模板類(lèi)對(duì)象來(lái)動(dòng)態(tài)的創(chuàng)建。我覺(jué)得這是每個(gè)MFC的學(xué)習(xí)者很希望理解的問(wèn)題。

  初次接觸MFC的時(shí)候,很容易有這樣的迷惘。MFC的幾大類(lèi)不用我們?cè)O(shè)計(jì)也就罷了,但最疑惑的是不用我們實(shí)例化對(duì)象。本來(lái)最直觀的理解就是,我們需要框架的時(shí)候,親手寫(xiě)上CFrameWnd myFrame;需要視的時(shí)候,親自打上CView myView;……

  但MFC不給我們這個(gè)機(jī)會(huì),致使我們錯(cuò)覺(jué)窗口沒(méi)有實(shí)例化就彈出來(lái)了!就象畫(huà)了張電視機(jī)的電路圖就可以看電視一樣令人難以置信。但大伙想了一下,可能會(huì)一拍腦門(mén),認(rèn)為簡(jiǎn)單不過(guò):MFC自動(dòng)幫我們完成CView myView之流的代碼不就行了么!??!其實(shí)不然,寫(xiě)MFC程序的時(shí)候,我們幾乎要對(duì)每個(gè)大類(lèi)進(jìn)行派生改寫(xiě)。換句話(huà)說(shuō),MFC并不知道我們打算怎樣去改寫(xiě)這些類(lèi),當(dāng)然也不打算全部為我們“靜態(tài)”創(chuàng)建這些類(lèi)了。即使靜態(tài)了創(chuàng)建這些類(lèi)也沒(méi)有用,因?yàn)槲覀儚膩?lái)也不會(huì)直接利用這些類(lèi)的實(shí)例干什么事情。我們只知道,想做什么事情就往各大類(lèi)里塞,不管什么變量、方法照塞,塞完之后,我們似乎并未實(shí)例化對(duì)象,程序就可以運(yùn)行!

  要做到把自己的類(lèi)交給MFC,MFC就用同一樣的方法,把不同的類(lèi)一一準(zhǔn)確創(chuàng)建,我們要做些什么事情呢?同樣地,我們要建立鏈表,記錄各類(lèi)的關(guān)鍵信息,在動(dòng)態(tài)創(chuàng)建的時(shí)候找出這些信息,就象上一節(jié)RTTI那樣!我們可以設(shè)計(jì)一個(gè)類(lèi):

struct CRuntimeClass{
 LPCSTR m_lpszClassName; //類(lèi)名指針
 CObject* (PASCAL *m_pfnCreateObject)(); //創(chuàng)建對(duì)象的函數(shù)的指針
 CRuntimeClass* m_pBaseClass; //講RTTI時(shí)介紹過(guò)
 CRuntimeClass* m_pNextClass; //指向鏈表的下一個(gè)元素(許多朋友說(shuō)上一節(jié)講RTTI時(shí)并沒(méi)有用到這個(gè)指針,我原本以為這樣更好理解一些,因?yàn)闆](méi)有這個(gè)指針,這個(gè)鏈表是無(wú)法連起來(lái),而m_pBaseClass僅僅是向基類(lèi)走,在MFC的樹(shù)型層次結(jié)構(gòu)中m_pBaseClass是不能遍歷的)

 CObject* CreateObject(); //創(chuàng)建對(duì)象
 static CRuntimeClass* PASCAL Load(); //遍歷整個(gè)類(lèi)型鏈表,返回符合動(dòng)態(tài)創(chuàng)建的對(duì)象。
 static CRuntimeClass* pFirstClass; //類(lèi)型鏈表的頭指針
};

  一下子往結(jié)構(gòu)里面塞了那么多的東西,大家可以覺(jué)得有點(diǎn)頭暈。至于CObject* (PASCAL *m_pfnCreateObject)();,這定義函數(shù)指針的方法,大家可能有點(diǎn)陌生。函數(shù)指針在C++書(shū)籍里一般被定為選學(xué)章節(jié),但MFC還是經(jīng)常用到此類(lèi)的函數(shù),比如我們所熟悉的回調(diào)函數(shù)。簡(jiǎn)單地說(shuō)m_pfnCreateObject即是保存了一個(gè)函數(shù)的地址,它將會(huì)創(chuàng)建一個(gè)對(duì)象。即是說(shuō),以后,m_pfnCreateObject指向不同的函數(shù),我們就會(huì)創(chuàng)建不同類(lèi)型的對(duì)象。

  有函數(shù)指針,我們要實(shí)現(xiàn)一個(gè)與原定義參數(shù)及返回值都相同一個(gè)函數(shù),在MFC中定義為:

static CObject* PASCAL CreateObject(){return new XXX};//XXX為類(lèi)名。類(lèi)名不同,我們就創(chuàng)建不同的對(duì)象。

  由此,我們可以如下構(gòu)造CRuntimeClass到鏈表:

CRuntimeClass classXXX={
 類(lèi)名,
 ……,
 XXX::CreateObject(), //m_pfnCreateObject指向的函數(shù)
 RUNTIME_CLASS(基類(lèi)名) // RUNTIME_CLASS宏可以返回CRuntimeClass對(duì)象指針。
 NULL //m_pNextClass暫時(shí)為空,最后會(huì)我們?cè)僭O(shè)法讓它指向舊鏈表表頭。
};

  這樣,我們用函數(shù)指針m_pfnCreateObject(指向CreateObject函數(shù)),就隨時(shí)可new新對(duì)象了。并且大家留意到,我們?cè)谠O(shè)計(jì)CRuntimeClass類(lèi)對(duì)時(shí)候,只有類(lèi)名(和基類(lèi)名)的不同(我們用XXX代替的地方),其它的地方一樣,這正是我們想要的,因?yàn)槲覀儎?dòng)態(tài)創(chuàng)建也象RTTI那樣用到兩個(gè)宏,只要傳入類(lèi)名和基類(lèi)作宏參數(shù),就可以滿(mǎn)足條件。

  即是說(shuō),我們類(lèi)說(shuō)明中使用DECLARE_DYNCREATE(CLASSNMAE)宏和在類(lèi)的實(shí)現(xiàn)文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏來(lái)為我們加入鏈表,至于這兩個(gè)宏怎么為我們建立一個(gè)鏈表,我們自己可以玩玩文字代換的游戲,在此不一一累贅。但要說(shuō)明的一點(diǎn)就是:動(dòng)態(tài)創(chuàng)建宏xxx_DYNCREATE包含了RTTI宏,即是說(shuō), xxx_DYNCREATE是xxx_DYNAMIC的“增強(qiáng)版”。

  到此,我們有必要了解一下上節(jié)課沒(méi)有明講的m_pNextClass指針。因?yàn)镸FC層次結(jié)構(gòu)是樹(shù)狀的,并不是直線(xiàn)的。如果我們只有一個(gè)m_pBaseClass指針,它只會(huì)沿著基類(lèi)上去,會(huì)漏掉其它分支。在動(dòng)態(tài)創(chuàng)建時(shí),必需要檢查整個(gè)鏈表,看有多少個(gè)要?jiǎng)討B(tài)創(chuàng)建的對(duì)象,即是說(shuō)要從表頭(pFirstClass)開(kāi)始一直遍歷到表尾(m_pNextClass=NULL),不能漏掉一個(gè)CRuntimeClass對(duì)象。

  所以每當(dāng)有一個(gè)新的鏈表元素要加入鏈表的時(shí)候,我們要做的就是使新的鏈表元素成為表頭,并且m_pNextClass指向原來(lái)鏈表的表頭,即像下面那樣(當(dāng)然,這些不需要我們操心,是RTTI宏幫助我們完成的):

pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;//新元素的m_pNextClass指針指向想加入的鏈表的表頭。

CRuntimeClass::pFirstClass=pNewClass;//鏈表的頭指針指向剛插入的新元素。

  好了,有了上面的鏈表,我們就可以分析動(dòng)態(tài)創(chuàng)建了。

  有一了張有類(lèi)名,函數(shù)指針,動(dòng)態(tài)創(chuàng)建函數(shù)的鏈表,我們就可以知道應(yīng)該按什么步驟去動(dòng)態(tài)創(chuàng)建了:

  1、獲得一要?jiǎng)討B(tài)創(chuàng)建的類(lèi)的類(lèi)名(假設(shè)為A)。

  2、將A跟鏈表里面每個(gè)元素的m_lpszClassName指向的類(lèi)名作比較。

  3、若找到跟A相同的類(lèi)名就返回A所屬的CRuntimeClass元素的指針。

  4、判斷m_pfnCreateObject是否有指向創(chuàng)建函數(shù),有則創(chuàng)建對(duì)象,并返回該對(duì)象。

  代碼演示如下(以下兩個(gè)函數(shù)都是CRuntimeClass類(lèi)函數(shù)):

  ///////////////以下為根據(jù)類(lèi)名從表頭向表尾查找所屬的CRuntimeClass對(duì)象////////////

CRuntimeClass* PASCAL CRuntimeClass::Load()
{
 char szClassXXX[64];
 CRuntimeClass* pClass;
 cin>>szClassXXX; //假定這是我們希望動(dòng)態(tài)創(chuàng)建的類(lèi)名
 for(pClass=pFirstClass;pClass!=NULL;pClass=pClass->m_pNextClass)
 {
  if(strcmp(szClassXXX,pClass->m_lpszClassName)==0)
   return pClass;
 }
 return NULL
}

///////////根據(jù)CRuntimeClass創(chuàng)建對(duì)象///////////

CObject* CRuntimeClass::CreateObject()
{
 if(m_pfnCreateObject==NULL) return NULL;
 CObject *pObject;
 pObject=(* m_pfnCreateObject)(); //函數(shù)指針調(diào)用
 return pObject;
}

  有了上面兩個(gè)函數(shù),我們?cè)诔绦驁?zhí)行的時(shí)候調(diào)用,就可以動(dòng)態(tài)創(chuàng)建對(duì)象了。

  我們還可以更簡(jiǎn)單地實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建,大家注意到,就是在我們的程序類(lèi)里面有一個(gè)RUNTIME_CLASS(class_name)宏,這個(gè)宏在MFC里定義為:

RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

  作用就是得到類(lèi)的RunTime信息,即返回class_name所屬CRuntimeClass的對(duì)象。在我們的應(yīng)用程序員類(lèi)(CMyWinApp)的InitInstance()函數(shù)下面的CSingleDocTemplate函數(shù)中,有:

RUNTIME_CLASS(CMyDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CMyView)

  構(gòu)造文檔模板的時(shí)候就用這個(gè)宏得到文檔、框架和視的RunTime信息。有了RunTime信息,我們只要一條語(yǔ)句就可以動(dòng)態(tài)創(chuàng)建了,如:

classMyView->CreateObject(); //對(duì)象直接調(diào)用用CRuntimeClass本身的CreateObject()

  現(xiàn)在,細(xì)心的朋友已經(jīng)能清楚動(dòng)態(tài)創(chuàng)建需要的步驟:

  1、定義一個(gè)不帶參數(shù)的構(gòu)造函數(shù)(默認(rèn)構(gòu)造函數(shù));因?yàn)槲覀兪怯肅reateObject()動(dòng)態(tài)創(chuàng)建,它只有一條語(yǔ)句就是return new XXX,不帶任何參數(shù)。所以我們要有一個(gè)無(wú)參構(gòu)造函數(shù)。

  2、類(lèi)說(shuō)明中使用DECLARE_DYNCREATE(CLASSNMAE)宏;和在類(lèi)的實(shí)現(xiàn)文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏;這個(gè)宏完成構(gòu)造CRuntimeClass對(duì)象,并加入到鏈表中。

  3、使用時(shí)先通過(guò)宏RUNTIME_CLASS得到類(lèi)的RunTime信息,然后使用CRuntimeClass的成員函數(shù)CreateObject創(chuàng)建一個(gè)該類(lèi)的實(shí)例。

  4、CObject* pObject = pRuntimeClass->CreateObject();//完成動(dòng)態(tài)創(chuàng)建。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(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)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多