MFC RTTI 探究
MFC RTTI 探究
张杰
2011-09-17
声明
本文由张杰原创,参考了侯俊杰先生的《深入浅出MFC》,源码摘自 Microsoft Visual Studio 9.0\VC。
个人能力有限,文章必定存在很多错误。我的邮箱是:chinajiezhang@gmail.com chinajiezhang@163.com 欢迎您来邮件斧正。当然您也可以加我 msn: chinazhangjie@hotmail.com 交流。
本文可供传播、交流、学习使用,但请不要用于商业用途。转载请标明此声明,谢谢您的合作。
DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE
查看DECLARE_DYNCREATE 定义(c:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afx.h):
#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name) \
static CObject* PASCAL CreateObject();
查看DECLARE_DYNAMIC定义(c:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afx.h):
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static const CRuntimeClass class##class_name; \
static CRuntimeClass* PASCAL GetThisClass(); \
virtual CRuntimeClass* GetRuntimeClass() const; \
不再有宏了,我们找个例子将代码展开看看效果(创建 MFC 单文档,命名为:FirstMFCDemo):
在FirstMFCDemoDoc.h下有行代码:
DECLARE_DYNCREATE(CFirstMFCDemoDoc)
展开代码为:
protected:
static CRuntimeClass* PASCAL _GetBaseClass();
public:
static const CRuntimeClass classCFirstMFCDemoDoc;
static CRuntimeClass* PASCAL GetThisClass();
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
先不管代码的具体含义,把 IMPLEMENT_DYNCREATE 宏定义看了再说(c:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afx.h):
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
class_name::CreateObject, NULL)
继续查看IMPLEMENT_RUNTIMECLASS定义(c:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afx.h):
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
CRuntimeClass* PASCAL class_name::_GetBaseClass() \
{ return RUNTIME_CLASS(base_class_name); } \
AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
&class_name::_GetBaseClass, NULL, class_init }; \
CRuntimeClass* PASCAL class_name::GetThisClass() \
{ return _RUNTIME_CLASS(class_name); } \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return _RUNTIME_CLASS(class_name); }
查看RUNTIME_CLASS和_RUNTIME_CLASS宏定义:
#define RUNTIME_CLASS(class_name) \
(class_name::GetThisClass())
#define _RUNTIME_CLASS(class_name) \
((CRuntimeClass*)(&class_name::class##class_name))
在 FirstMFCDemoDoc.cpp 找到代码:
IMPLEMENT_DYNCREATE(CFirstMFCDemoDoc, CDocument)
展开后为:
CObject* PASCAL CFirstMFCDemoDoc::CreateObject() \
{ return new CFirstMFCDemoDoc; } \
CRuntimeClass* PASCAL CFirstMFCDemoDoc::_GetBaseClass() \
{ return CDocument::GetThisClass(); } \
AFX_COMDAT const CRuntimeClass CFirstMFCDemoDoc::classCFirstMFCDemoDoc = {
#CFirstMFCDemoDoc, sizeof(class CFirstMFCDemoDoc), 0xFFFF, CFirstMFCDemoDoc::CreateObject, \
&CFirstMFCDemoDoc::_GetBaseClass, NULL, NULL }; \
CRuntimeClass* PASCAL CFirstMFCDemoDoc::GetThisClass() \
{ return (CRuntimeClass*)(&CFirstMFCDemoDoc::classCFirstMFCDemoDoc); } \
CRuntimeClass* CFirstMFCDemoDoc::GetRuntimeClass() const \
{ return (CRuntimeClass*)(&CFirstMFCDemoDoc::classCFirstMFCDemoDoc); }
好乱的团代码啊,我们来理理:
DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE为类 CFirstMFCDemoDoc 添加了3个静态函数1个虚函数1静态CRuntimeClass 类型常量,以及代码实现体。分别为:
public:
virtual
CObject* PASCAL CFirstMFCDemoDoc::CreateObject()
{
return new CFirstMFCDemoDoc;
}
protected:
static
CRuntimeClass* PASCAL CFirstMFCDemoDoc::_GetBaseClass()
{
return CDocument::GetThisClass();
}
static
AFX_COMDAT const CRuntimeClass
CFirstMFCDemoDoc::classCFirstMFCDemoDoc = {
#CFirstMFCDemoDoc,
sizeof(class CFirstMFCDemoDoc),
0xFFFF,
CFirstMFCDemoDoc::CreateObject,
&CFirstMFCDemoDoc::_GetBaseClass,
NULL,
NULL
};
CRuntimeClass* PASCAL CFirstMFCDemoDoc::GetThisClass()
{
return(CRuntimeClass*)(&CFirstMFCDemoDoc::classCFirstMFCDemoDoc);
}
CRuntimeClass* CFirstMFCDemoDoc::GetRuntimeClass() const
{
return(CRuntimeClass*)(&CFirstMFCDemoDoc::classCFirstMFCDemoDoc);
}
想要知道这些代码到底在干什么,就必须了解 CRunTimeClass 是干什么的?废话不说,直接上 CRuntimeClass 源码(c:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afx.h):
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
#ifdef _AFXDLL
CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
#else
CRuntimeClass* m_pBaseClass;
#endif
// Operations
CObject* CreateObject();
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
// dynamic name lookup and creation
static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
// Implementation
void Store(CArchive& ar) const;
static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
// CRuntimeClass objects linked together in simple list
CRuntimeClass* m_pNextClass; // linked list of registered classes
const AFX_CLASSINIT* m_pClassInit;
};
查看 AFX_CLASSINIT 类型定义:
struct AFX_CLASSINIT
{ AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
继续查看 AfxClassInit 定义:
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
pModuleState->m_classList.AddHead(pNewClass);
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
}
由此看出,AFX_CLASSINIT结构完成了链表的链接操作,我们不做深究。
MFC 每个类基本都有一个 CRuntimeClass 类型的对象,这些对象构成了一个链表。链表的头是谁呢?答案是CObject,它是MFC所有类的祖先类。这个链表记录了类的名称、链表的Next指针、类的基类指针等等操作。我们可以用这些记录来比较, 以达到 RTTI 的能力。
我百度了几张图片(事实上,这是《深入浅出MFC》中的图片,至少长的很像,O(∩_∩)O~),便于理解 RTTI :
好吧,就讲到这里了。能力有限,再深也就看你们的了。