追根究底,MFC六大關鍵技術剖析(三)

2021-05-28 03:23:42 字數 3427 閱讀 7461

三、動態建立

動態建立就是執行時建立指定類的物件,在mfc中大量使用。如框架視窗物件、視物件,還有文件物件都需要由文件模板類物件來動態的建立。我覺得這是每個mfc的學習者很希望理解的問題。

初次接觸mfc的時候,很容易有這樣的迷惘。mfc的幾大類不用我們設計也就罷了,但最疑惑的是不用我們例項化物件。本來最直觀的理解就是,我們需要框架的時候,親手寫上cframewnd myframe;需要視的時候,親自打上cview myview;……

但mfc不給我們這個機會,致使我們錯覺視窗沒有例項化就彈出來了!就象畫了張電視機的電路圖就可以看電視一樣令人難以置信。但大夥想了一下,可能會一拍腦門,認為簡單不過:mfc自動幫我們完成cview myview之流的**不就行了麼!!!其實不然,寫mfc程式的時候,我們幾乎要對每個大類進行派生改寫。換句話說,mfc並不知道我們打算怎樣去改寫這些類,當然也不打算全部為我們「靜態」建立這些類了。即使靜態了建立這些類也沒有用,因為我們從來也不會直接利用這些類的例項幹什麼事情。我們只知道,想做什麼事情就往各大類裡塞,不管什麼變數、方法照塞,塞完之後,我們似乎並未例項化物件,程式就可以執行!

要做到把自己的類交給mfc,mfc就用同一樣的方法,把不同的類一一準確建立,我們要做些什麼事情呢?同樣地,我們要建立鍊錶,記錄各類的關鍵資訊,在動態建立的時候找出這些資訊,就象上一節rtti那樣!我們可以設計乙個類:

struct cruntimeclass;//***為類名。類名不同,我們就建立不同的物件。

由此,我們可以如下構造cruntimeclass到鍊錶:

cruntimeclass class***=;

這樣,我們用函式指標m_pfncreateobject(指向createobject函式),就隨時可new新物件了。並且大家留意到,我們在設計cruntimeclass類對時候,只有類名(和基類名)的不同(我們用***代替的地方),其它的地方一樣,這正是我們想要的,因為我們動態建立也象rtti那樣用到兩個巨集,只要傳入類名和基類作巨集引數,就可以滿足條件。

即是說,我們類說明中使用declare_dyncreate(classnmae)巨集和在類的實現檔案中使用implement_dyncreate(classname,baseclass)巨集來為我們加入鍊錶,至於這兩個巨集怎麼為我們建立乙個鍊錶,我們自己可以玩玩文字代換的遊戲,在此不一一累贅。但要說明的一點就是:動態建立巨集***_dyncreate包含了rtti巨集,即是說, ***_dyncreate是***_dynamic的「增強版」。

到此,我們有必要了解一下上節課沒有明講的m_pnextclass指標。因為mfc層次結構是樹狀的,並不是直線的。如果我們只有乙個m_pbaseclass指標,它只會沿著基類上去,會漏掉其它分支。在動態建立時,必需要檢查整個鍊錶,看有多少個要動態建立的物件,即是說要從表頭(pfirstclass)開始一直遍歷到表尾(m_pnextclass=null),不能漏掉乙個cruntimeclass物件。

所以每當有乙個新的鍊錶元素要加入鍊錶的時候,我們要做的就是使新的鍊錶元素成為表頭,並且m_pnextclass指向原來鍊錶的表頭,即像下面那樣(當然,這些不需要我們操心,是rtti巨集幫助我們完成的):

pnewclass->m_pnextclass=cruntimeclass::pfirstclass;//新元素的m_pnextclass指標指向想加入的鍊錶的表頭。

cruntimeclass::pfirstclass=pnewclass;//鍊錶的頭指標指向剛插入的新元素。

好了,有了上面的鍊錶,我們就可以分析動態建立了。

有一了張有類名,函式指標,動態建立函式的鍊錶,我們就可以知道應該按什麼步驟去動態建立了:1、獲得一要動態建立的類的類名(假設為a)。2、將a跟鍊錶裡面每個元素的m_lpszclassname指向的類名作比較。3、若找到跟a相同的類名就返回a所屬的cruntimeclass元素的指標。4、判斷m_pfncreateobject是否有指向建立函式,有則建立物件,並返回該物件。**演示如下(以下兩個函式都是cruntimeclass類函式):

///以下為根據類名從表頭向表尾查詢所屬的cruntimeclass物件

cruntimeclass* pascal cruntimeclass::load()

char szclass***[64];

cruntimeclass* pclass;

cin>>szclass***;      //假定這是我們希望動態建立的類名

for(pclass=pfirstclass;pclass!=null;pclass=pclass->m_pnextclass)

if(strcmp(szclass***,pclass->m_lpszclassname)==0)

return pclass;

return null

///根據cruntimeclass建立物件///

cobject* cruntimeclass::createobject()

if(m_pfncreateobject==null) return null;

cobject *pobject;

pobject=(* m_pfncreateobject)();              //函式指標呼叫

return pobject;                                  

有了上面兩個函式,我們在程式執行的時候呼叫,就可以動態建立物件了。

runtime_class(class_name)  ((cruntimeclass*)(&class_name::class##class_name))

runtime_class(cmydoc),

runtime_class(cmainframe),       // main sdi frame window

runtime_class(cmyview)

構造文件模板的時候就用這個巨集得到文件、框架和視的runtime資訊。有了runtime資訊,我們只要一條語句就可以動態建立了,如:

classmyview->createobject();      //物件直接呼叫用cruntimeclass本身的createobject()

現在,細心的朋友已經能清楚動態建立需要的步驟:

1、定義乙個不帶引數的建構函式(預設建構函式);因為我們是用createobject()動態建立,它只有一條語句就是return new ***,不帶任何引數。所以我們要有乙個無參建構函式。

2、類說明中使用declare_dyncreate(classnmae)巨集;和在類的實現檔案中使用implement_dyncreate(classname,baseclass)巨集;這個巨集完成構造cruntimeclass物件,並加入到鍊錶中。

3、使用時先通過巨集runtime_class得到類的runtime資訊,然後使用cruntimeclass的成員函式createobject建立乙個該類的例項。

4、cobject* pobject = pruntimeclass->createobject();//完成動態建立。

追根究底,MFC六大關鍵技術之剖析(二)

追根究底,mfc六大關鍵技術之剖析 二 二 執行時型別識別 rtti 執行時型別識別 rtti 即是程式執行過程中知道某個物件屬於某個類,我們平時用c 程式設計接觸的rtti一般是編譯器的rtti,即是在新版本的vc 編譯器裡面選用 使能rtti 然後載入typeinfo.h檔案,就可以使用乙個叫t...

追根究底,MFC六大關鍵技術之剖析(2)

追根究底,mfc六大關鍵技術之剖析 第二部分 小李先生 二 執行時型別識別 rtti 執行時型別識別 rtti 即是程式執行過程中知道某個物件屬於某個類,我們平時用c 程式設計接觸的rtti一般是編譯器的rtti,即是在新版本的vc 編譯器裡面選用 使能rtti 然後載入typeinfo.h檔案,就...

追根究底, 六大關鍵技術剖析(第三部分)

三 動態建立 動態建立就是執行時建立指定類的物件,在 mfc 中大量使用。如框架視窗物件 視物件,還有文件物件都需要由文件模板類物件來動態的建立。我覺得這是每個 mfc 的學習者很希望理解的問題。初次接觸 mfc 的時候,很容易有這樣的迷惘。mfc 的幾大類不用我們設計也就罷了,但最疑惑的是不用我們...