MFC框架早在標準C++之間提出並實現了類的運行時識別(RTTI)功能,下面記錄下基於我對其的理解。 框架
要實現RTTI必須在定義的時候記錄下來類的基本信息。MFC構建了一個CRuntimeClass的結構體用以保存類的基本信息。CRun提麼Class的定義以下: 函數
struct CRuntimeClass { LPCSTR m_pszClassName; //類名稱 int m_nObjectSize; //類的大小 UINT m_wSchema; CObject (PASCAL * m_pfnCreateObject)(); CRuntimeClass *m_pBaseClass; //類的基類(父類) static CRuntimeClass *pFirstClass;//保存類信息的鏈表頭指針 CRuntimeClass *m_pNextClass;//鏈表的下一個 };在定義好這樣一個結構體後,在每一個類中添加一個這樣的成員(靜態的)便可。這樣的每一個實例均可以經過該屬性訪問到類的相關信息。這樣的定義是屬於類的全部對象共有的,在定義類的時候就已經定義好了,因此只須要將該屬性定義爲靜態的便可。經過這種作法每一個類都保存的類的全部相關信息,可是若是要查找類的相關信息是不夠的,因此經過鏈表的方式將這些類的CRuntimeClass靜態屬性組織起來,這樣能夠遍歷程序中的全部類,也能夠方便查找了。
其具體實現方式爲,在MFC框架中定義個DECLARE_DYNAMIC(class_name)的宏,使用宏來實現自動添加該成員(屬性)。該宏的具體定義爲: spa
#define DECLARE_DYNAMIC(class_name) \ //class_name爲類的名稱 public: \ static CRuntimeClass class##class_name;\ //定義類中的靜態成員 ,將該成員的名稱固定爲class+類名稱的形式 virtual CRuntimeClass *GetRuntimeClass() const;//定義一個類的返回類相關信息的函數,該函數返回一個CRuntimeClass的指針,該指針指向類的靜態成員變量(及前面定義的CRuntimeClass class##class_name)上面的步驟定義了類中的CRuntimeClass,可是並未提供相應的實現。因此MFC框架繼續定義了一個IMPLEMENT_DYNAMIC(class_name,base_class_name)的宏用以實現。其具體定義爲:
struct AFX_CLASSINIT { AFX_CLASSINIT(CRuntimeClass *pNewClass); }; //定義該結構體主要是爲了下面的宏定義中修改保存類信息鏈表的相關信息,將當前類的靜態成員CRuntimeClass添加到鏈表頭。 #define RUNTIME_CLASS(class_name) \ (&class_name::class##class_name)\\用於下面的宏中返回類中靜態成員CRuntimeClass的地址。 #define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew) \ static char _lpsz##class_name[]=#class_name;\ //定義一個文件域的變量用以保存類的名稱(字符串常量) CRuntimeClass class_name::class##class_name={\ _lpsz##class_name,sizeof(class_name),wSchema,pfnNew,RUNTIME_CLASS(base_class_name),NULL};\ \\定義類中的靜態成員CRuntimeClass class##class_name,這裏麪包括類的名稱,類的大小,父類等。這裏須要注意的是這裏的定義並無改變該結構體中的靜態成員變量——指向保存類信息的鏈表頭。 static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name);\ //定義另外一個結構體經過使用該結構的構造方法來實現將鏈表的頭指針指向當前類的CRuntimeClass,將下一個指針指向鏈表中之前的頭,這樣就將全部類中的CRuntimeClass信息經過鏈表鏈接起來。 CRuntimeClass *class_name::GetRuntimeClass() const \ {return &class_name::class##class_name;}\ \\定義類中的獲取成員變量CRuntimeClass的具體實現。 #define IMPLEMENT_DYNAMIC(class_name,base_class_name) \ _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0XFFFF,NULL)上面的這些就是MFC種的RTTI的仿真。須要注意的是,CRuntimeClass的鏈表中,利用了在鏈表頭插入的方式(對於單鏈表而言,這應該比較快捷的方法),因此最後添加的類的相關信息在鏈表的標頭位置。另外還須要注意的,這裏鏈表的頭在初始化的時候並無初始化,因此對於全部類的父類及CObject類而言,不能經過簡單的DELCARE_DYNAMIC、IMPLEMENT_DYNAMIC宏來實現。