動態建立就是執行時建立指定類的物件,在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中的六大關鍵技術
1 mfc程式的初始化工作 在mfc中所有的類都 於乙個基類 cobject。mfc程式初始化過程中,其實就是虛函式的呼叫的過程,分清呼叫執行的到底是哪乙個具體的虛函式,是父類的虛函式,還是基類的虛函式,都是至關重要的。2 rtti執行時型別識別 mfc程式執行過程中需要對類的型別進行動態的判斷。在...
追根究底,MFC六大關鍵技術剖析(三)
三 動態建立 動態建立就是執行時建立指定類的物件,在mfc中大量使用。如框架視窗物件 視物件,還有文件物件都需要由文件模板類物件來動態的建立。我覺得這是每個mfc的學習者很希望理解的問題。初次接觸mfc的時候,很容易有這樣的迷惘。mfc的幾大類不用我們設計也就罷了,但最疑惑的是不用我們例項化物件。本...
MFC六大關鍵技術之執行時型別識別
執行時型別識別 rtti 即是程式執行過程中知道某個物件屬於某個類,我們平時用c 程式設計接觸的rtti一般是編譯器的rtti,即是在新版本的vc 編譯器裡面選用 使能rtti 然後載入typeinfo.h檔案,就可以使用乙個叫typeid 的運運算元,它的地位與在c 程式設計中的sizeof 運運...