三、動態建立
動態建立就是執行時建立指定類的物件,在
mfc 中大量使用。如框架視窗物件、視物件,還有文件物件都需要由文件模板類物件來動態的建立。我覺得這是每個
mfc 的學習者很希望理解的問題。
初次接觸
mfc 的時候,很容易有這樣的迷惘。
mfc 的幾大類不用我們設計也就罷了,但最疑惑的是不用我們例項化物件。本來最直觀的理解就是,我們需要框架的時候,親手寫上
cframewnd myframe
;需要視的時候,親自打上
cview myview;
…… 但mfc
不給我們這個機會,致使我們錯覺視窗沒有例項化就彈出來了!就象畫了張電視機的電路圖就可以看電視一樣令人難以置信。但大夥想了一下,可能會一拍腦門,認為簡單不過:
mfc 自動幫我們完成
cview myview
之流的**不就行了麼!!!其實不然,寫
mfc 程式的時候,我們幾乎要對每個大類進行派生改寫。換句話說,
mfc 並 不知道我們打算怎樣去改寫這些類,當然也不打算全部為我們「靜態」建立這些類了。即使靜態了建立這些類也沒有用,因為我們從來也不會直接利用這些類的例項 幹什麼事情。我們只知道,想做什麼事情就往各大類裡塞,不管什麼變數、方法照塞,塞完之後,我們似乎並未例項化物件,程式就可以執行!
要做到把自己的類交給
mfc ,
mfc 就用同一樣的方法,把不同的類一一準確建立,我們要做些什麼事情呢?同樣地,我們要建立鍊錶,記錄各類的關鍵資訊,在動態建立的時候找出這些資訊,就象上一節
rtti
那樣!我們可以設計乙個類:
struct cruntimeclass;
一下子往結構裡面塞了那麼多的東西,大家可以覺得有點頭暈。至於
cobject* (pascal *m_pfncreateobject)();
,這定義函式指標的方法,大家可能有點陌生。函式指標在
c++ 書籍裡一般被定為選學章節,但
mfc 還是經常用到此類的函式,比如我們所熟悉的**函式。簡單地說
m_pfncreateobject
即是儲存了乙個函式的位址,它將會建立乙個物件。即是說,以後,
m_pfncreateobject
指向不同的函式,我們就會建立不同型別的物件。
有函式指標,我們要實現乙個與原定義引數及返回值都相同乙個函式,在
mfc 中定義為:
static cobject* pascal createobject();//***
為類名。類名不同,我們就建立不同的物件。
由此,我們可以如下構造
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()
return null
} /// 根據
cruntimeclass
建立物件
///
cobject* cruntimeclass::createobject()
有了上面兩個函式,我們在程式執行的時候呼叫,就可以動態建立物件了。
我們還可以更簡單地實現動態建立,大家注意到,就是在我們的程式類裡面有乙個
runtime_class(class_name)
巨集,這個巨集在
mfc 裡定義為:
runtime_class(class_name) ((cruntimeclass*)(&class_name::class##class_name))
作用就是得到類的
runtime
資訊,即返回
class_name
所屬cruntimeclass
的物件。在我們的應用程式設計師類
的initinstance()
函式下面的
csingledoctemplate
函式中,有:
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();//
完成動態建立。
摘自:http://blog.csdn.net/liyi268/archive/2005/03/04/310895.aspx
追根究底,MFC六大關鍵技術剖析(三)
三 動態建立 動態建立就是執行時建立指定類的物件,在mfc中大量使用。如框架視窗物件 視物件,還有文件物件都需要由文件模板類物件來動態的建立。我覺得這是每個mfc的學習者很希望理解的問題。初次接觸mfc的時候,很容易有這樣的迷惘。mfc的幾大類不用我們設計也就罷了,但最疑惑的是不用我們例項化物件。本...
追根究底,MFC六大關鍵技術之剖析(二)
追根究底,mfc六大關鍵技術之剖析 二 二 執行時型別識別 rtti 執行時型別識別 rtti 即是程式執行過程中知道某個物件屬於某個類,我們平時用c 程式設計接觸的rtti一般是編譯器的rtti,即是在新版本的vc 編譯器裡面選用 使能rtti 然後載入typeinfo.h檔案,就可以使用乙個叫t...
追根究底,MFC六大關鍵技術之剖析(2)
追根究底,mfc六大關鍵技術之剖析 第二部分 小李先生 二 執行時型別識別 rtti 執行時型別識別 rtti 即是程式執行過程中知道某個物件屬於某個類,我們平時用c 程式設計接觸的rtti一般是編譯器的rtti,即是在新版本的vc 編譯器裡面選用 使能rtti 然後載入typeinfo.h檔案,就...