MFC動態建立(dynamic creation)實現原理

來源:互聯網
上載者:User
文章目錄
  • 1.CRuntimeClass的定義
  • 2.宏DECLARE_DYNCEATE
  • 3.宏IMPLEMENT_DYNCREATE
  • 4.建立對象

在用到MFC的文檔視圖構架你可能有個非常迷惑的地方.就是很多類不知道在哪裡就被莫名其妙的執行個體化了.

以單文檔視圖為例.代碼中你能看到的的執行個體化的地方就只有兩個一個是CWinApp的一個全域變數的執行個體化,另一個就是
CSingleDocTemplate 執行個體化.它的建構函式如下

CSingleDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,

CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);

然後接下來的事就你迷惑了,先是繼承自SingleDocTemplate的類執行個體化了繼承自CFrameWnd的類和繼承自CDocument的類,然後呢繼承自CFrameWnd的類又執行個體化了繼承自CView的類.

你可能會想到背後早有寫好的代碼去執行個體化這些類了,但是最令你疑惑的是我自己定義繼承自啥CView,CDocument等類的類時名字是自己隨便取的啊,之前寫好的代碼竟然能有未蔔Crowdsourced Security Testing的能力知道這類名? 不然不知道一個類的類名怎麼去執行個體化它啊?

MFC自然沒這麼神奇的能力.所以毫無疑問的一點是你定義的新類類名資訊肯定會傳到某個地方,然後在那裡執行個體化該類.背後的機制咋樣的呢?

這就是所謂的動態產生(dynamic creation)機制了啊.該機制有用到前面講的RTTI,在RTTI的基礎上再擴充一些功能.

 

動態建立的一個簡單例子1.CRuntimeClass的定義

首先CRuntimeClass定義中除了RTTI資訊,添加

struct CRuntimeClass{

CObject* ( *m_pfnCreateObject)(); //函數指標,指向的函數中會通過new執行個體化一個對象

CObject* CreateObject()

//其他資訊省略掉了

}

其中函數CreateObject定義如下

CObject* CRuntimeClass::CreateObject(){

CObject* pObect = NULL;

pObject =(*m_pfnCreateObject)();

}

 

2.宏DECLARE_DYNCEATE

假如定義一個繼承自CDocument的類CMyDoc.

我們瞧下CSingleDocTemplate* pTmp = new(.... RUNTIME_CLASS(CMyDoc) ....) //這裡忽略其他參數.

CMyDoc是怎麼被建立的呢? 先看CMyDoc定義中的宏

 

////////CMyDoc標頭檔//////

DECLARE_DYNCEATE(CMyDoc)

///////////////////////////////////////////////

相當於:

static CObject* CreateObject();

static CRuntimeClass classCMyDoc;

 

宏定義:

#define DECLARE_DYNCREATE(class_name) \

DECLARE_DYNAMIC(class_name) \

static CObject*  CreateObject();

 

3.宏IMPLEMENT_DYNCREATE

///////////CMyDoc cpp檔案/////////////////

IMPLEMENT_DYNCREATE(CMyDoc, CDocument)

/////////////////////////////////////////////////

上面的宏除了前面的RTTI資訊外,還有個

CObject*  CMyDoc::CreateObject(){

return new CMyDoc;

}

CMyDoc::classCMyDoc.m_pfnCreateObject = CMyDoc::CreateObject;

 

宏定義:

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \

CObject* class_name::CreateObject() \

{ return new class_name; } \

//IMPLEMENT_RUNTIMECLASS(......)//為討論方便這裡省略掉了

 

4.建立對象

有了上面兩個宏,然後CSingleDocTemplate的建構函式中有個參數RUNTIME_CLASS(CMyDoc),我們知道

#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())

的以傳的參數實際上是一個指向CMyView中的static CRuntimeClass classCMyDoc的指標.

於是可以這樣調用函數建立對象

CObject* pDoc = RUNTIME_CLASS(CMyDoc)->CreateObject();//實際上就是調用

CObject* CMyDoc::CreateObject(){

return new CMyDoc;

}

 

 

總結:

你可能看到上面一堆亂七八糟的東東,就想著真他媽扯蛋啊,搞到最後不就是只需要一個類的名字,然後用該名字來執行個體化一個類嘛.有必要搞得這麼麻煩嘛

該功能說起來簡單,但實現起來還真沒其他簡單方法啊,除非C++文法做些更改,編譯器添加些額外支援.我們知道函數中可以隨便傳個啥參數.

但執行個體化一個類比如CView* view = new CView; //一個類的名字是不能做為參數的啊.

比如void CreateObject(string className){

className* view = new className;

}

這樣的函數絕對無法通過編譯的.但我們上面講到的貌似是這樣實現的.因為那是宏,只是簡單的文字替換,宏的替換那一步還沒有輪到編譯器去幹活.宏替換完了才是編譯器上場.

有了宏可以把類名當"參數"一樣用可以說實現了一大半功能了.實際上你如果只是通過前面的兩個宏整出一個靜態函數static CObject* CreateObject();完全就可以了.但這樣顯然實現的不夠優雅嘛,並且既然有個CRuntimeClass了就乾脆把動態建立對象的函數帶到該結構體中豈不更好啊(很多地方都用到CRuntimeClass,動態類型識別,動態建立,序列化).

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.