DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏的詳細解釋

來源:互聯網
上載者:User

原文: http://blog.chinaunix.net/uid-26881496-id-3175819.html

ECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏的詳細解釋
最近有些朋友在看《深入淺出MFC》的時候,被第三章的幾個宏給卡住了,記得我第一次看此書時,也被這幾個宏給卡住。當然真正卡人的其實是第一個,也就是 DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC。我做了一個詳解,供同樣被卡住的朋友做個參考:)

說明:這兩個宏的主要目的,是在所指定的class(比如CView)的聲明和實現裡,加上一些靜態成員函數和靜態成員變數。所以,不要管“\”這個換行標誌,就把裡面的每一句話當作是在類裡的聲明或者是實現。另外,“##”和"#"符號我就不不贅述了。
另外,建議結合《深入淺出MFC》這本書,JJHou寫了一些展開宏的執行個體,結合執行個體看這個解釋可能效果會比較好一點:)

DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC

#define DECLARE_DYNAMIC(class_name)\
public:\
static CRuntimeClass class##class_name;\
//聲明一個類型為CRuntimeClass的靜態public成員變數,變數名是由字串"class"
//與所指定的類的類名組成。舉例而言,如果你寫DECLARE_DYNAMIC(CMyView),則等於聲明了一個
// static CRuntimeClass classCMyView靜態變數

virtual CRuntimeClass* GetRuntimeClass() const;\
//聲明一個虛函數,函數名為GetRuntimeClass,傳回值為CRuntimeClass類型的指標
//無參數,並且是個const函數

#define IMPLEMENT_DYNAMIC(class_name,bass_class_name)\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)

#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\
static char _lpsz##class_name[]= #class_name;\
//定義一個C類型字串靜態變數,變數名由"_lpsz"和指定類的類名組成,變數值為該指定類型的名字
//比如是CMyView,那麼定義的就是static char _lpszCMyView="CMyView";

CRuntimeClass class_name::class##class_name = {\
_lpsz##class_name,sizeof(class_name),wSchema,pfnNew,\
RUNTIME_CLASS(base_class_name),NULL};\
//給之前在DECLARE_DYNAMIC裡定義的CRuntimeClass類型的靜態成員變數賦值
//當然,除最後一個m_pNextClass沒有賦值(賦值為NULL,它由下面的結構處理)

static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name);\
//初始化一個名為"_init_##class_name"的AFX_CLASSINIT靜態結構,主要作用是給指定的class_name的
//class##class_name靜態變數的最後一個成員m_pNextClass賦值,具體見下面解釋AFX_CLASSINIT中

CRuntimeClass* class_name::GetRuntimeClass

() const\
{ return &class_name::class##class_name;}\
//之前在DECLARE_DYNAMIC裡定義的GetRuntimeClass的實現,很簡單,就一個return語句。

#define RUNTIME_CLASS(class_name)\
(&class_name::class##class_name)
//這部分之所以單獨define出一個宏,主要是為了方便從某個指定的class直接得到它的CRuntimeclass靜態成員

//以下是解釋AFX_CLASSINIT結構,注意,這不是一個宏,請回本貼就可以看下面內容

本帖隱藏的內容需要回複才可以瀏覽

[ 本帖最後由 成為高手 於 2008-10-29 08:49 編輯 ]

學mfc學到文檔,視圖和架構的時候,知道必須在這三個類的衍生類別的類聲明
裡加上DECLARE_DYNCREATE,然後在類聲明外合適的地方加上IMPLEMENT_DYNCREA
TE,然後文檔,視圖和架構,還有文件範本就可以協調工作了。查看msdn,發現
類似的宏有這幾對:
DECLARE_DYNAMIC 和 IMPLEMENT_DYNAMIC
DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE
DECLARE_SERIAL 和 IMPLEMENT_SERIAL

雖然msdn裡介紹了他們的作用,但對於它們為什麼會起這樣的作用心裡卻沒
底,於是翻了翻mfc的原始碼,喜歡鑽牛角尖的人可以和我一起來鑽一鑽。

1。
RUNTIME_CLASS宏的定義是這樣的:
#define RUNTIME_CLASS(class_name)
((CRuntimeClass*)(&class_name::class##class_name))
其中##的意思是把##兩邊的符號都進行宏擴充(如果它們是宏的話),然後把擴充
後的內容串連在一起,中間不加空格。例如:RUNTIME_CLASS(CView)將被擴充成

(CRuntimeClass*)(&CView::classCView)
但這個classCView是什麼意思?原來,classCView是由DECLARE_DYNAMIC(CView)
引入的一個public屬性的CRuntimeClass類型的靜態成員變數:
static const AFX_DATA CRuntimeClass classCView;

原來RUNTIME_CLASS的作用就是引用由DECLARE_DYNAMIC宏引入的靜態成員變
量。

2。DECLARE_DYNAMIC(class_name)
由於篇幅的原因,宏的具體定義代碼就不列出來了,感興趣的可以去看檔案
afx.h。
該宏往類中聲明了三個成員:
protected:
static CRuntimeClass* PASCAL _GetBaseClass();
public:
virtual CRuntimeClass* GetRuntimeClass() const;
static const AFX_DATA CRuntimeClass class##class_name;

有兩個成員函數,一個靜態成員變數class+類名,同RUNTIME_CLASS相似,如
果是DECLARE_DYNAMIC(CView)的話,這個靜態成員變數將是classCView。可見這
個成員變數的名稱是和DECLARE_DYNAMIC的參數有關的。在下文我們把這個成員變
量統統記做class##class_name。

這個靜態成員和兩個成員函數在哪裡被初始化和具體實現呢?原來是在IMPL
EMENT_DYNAMIC宏裡。

3。IMPLEMENT_DYNAMIC(class_name, base_class_name)
查看它的宏定義,如果_AFXDLL被定義了的話,由DECLARE_DYNAMIC引入的成
員的初始化和實現是這樣的:

CRuntimeClass* PASCAL class_name::_GetBaseClass()
{
return RUNTIME_CLASS(base_class_name);
}
CRuntimeClass* class_name::GetRuntimeClass() const
{
return RUNTIME_CLASS(class_name);
}
AFX_COMDAT const AFX_DATADEF
CRuntimeClass class_name::class##class_name =
{
#class_name,
sizeof(class class_name),
0xFFFF,
NULL,
NULL,
&class_name::_GetBaseClass,
NULL
};//這是在初始化靜態成員變數class##class_name。
//CRuntimeClass結構的各個成員的意義可查看msdn。

4。_DECLARE_DYNAMIC(class_name)
該宏的定義和DECLARE_DYNAMIC(class_name)基本一樣。不同之處是靜態成員
class##class_name前面沒有const修飾符。

5。DECLARE_DYNCREATE(class_name)

該宏也往類中引入了DECLARE_DYNAMIC宏所引入的那三個成員。除此之外,它
還另外引入了一個成員:
static CObject* PASCAL CreateObject();
該宏引入的成員在IMPLEMENT_DYNCREATE裡初始化和實現。

6。IMPLEMENT_DYNCREATE(class_name, base_class_name)
該宏自然是初始化和實現由DECLARE_DYNCREATE引入的成員了。
我們看看CreateObject的實現:
CObject* PASCAL class_name::CreateObject()
{
{
return new class_name;
}
呵,這個函數是如此簡單,它就是用CObject類裡重載的new操作符建立一個
該類類型的對象。

7。_DECLARE_DYNCREATE(class_name)
該宏引入了和DECLARE_DYNCREATE引入的四個成員差不多的成員。唯一的區別
是該宏引入的靜態成員class##class_name前面沒有const修飾符。

8。DECLARE_SERIAL(class_name)
該宏引入了和_DECLARE_DYNCREATE所引入的一樣的四個

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.