MFC RTTI 实现
——摘自侯俊杰《深入浅出MFC》
1.为了支持RTTI,MFC引入了CRuntimeClass的定义,定义如下:
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 // 存放函数指针,用于动态创建对象
CRuntimeClass *m_pBaseClass;
//调用m_pfnCreateObject动态创建对象
CObject* CreateObject();
//CRuntimeClass objects linked together in simple list
static CRuntimeClass* pFirstClass;//start of class list
CRuntimeClass* m_pNextClass;//linked list of registerd classes
};
2. DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏
DECLARE_DYNAMIC定义为(.h):
#define DECLARE_DYNAMIC(class_name)/
public:/
static CRuntimeClass class##class_name;/
virtual CRuntimeClass* GetRuntimeClass()const;
例如:
DECLARE_DYNAMIC(CView)
预处理后的代码实际为:
public:
static CRuntimeClass classCView ;
virtual CRuntimeClass* GetRuntimeClass()const;
//给我们定义了一个静态变量classCView和声明了一个虚函数GetRuntimeClass
//正是使用classCView 来实现了RTTI功能。
IMPLEMENT_DYNAMIC宏定义为(.cpp):
#define IMPLIMENT_DYNAMIC(class_name,base_class_name)/
_IMPLIMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)
IMPLIMENT_RUNTIMECLASS宏定义如下:
#define IMPLIMENT_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}/
static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name);/
CRuntimeClass* class_name::GetRuntimeClass()const/
{return &class_name::class##class_name;}/
RUNTIME_CLASS宏,定义如下:
#define RUNTIME_CLASS(class_name)/
(&class_name::class##class_name)
看起来整个IMPLIMENT_DYNAMIC内容好像只是指定初值,其实不然,其关键在于使用了struct AFX_CLASSINIT,并调用了其构造函数,实现了linked list的连接工作(把classXXX加入到类型表中),定义如下:
struct AFX_CLASSINIT
{
AFX_CLASSINIT(CRuntimeClass* pNewClass);//构造函数
}
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
{
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
CRuntimeClass::pFirstClass = pNewClass;
}
例如:
//in header file
class CView: public CWnd
{
DECLARE_DYNAMIC(CView)
...
};
//in implementation file
IMPLEMENT_DYNAMIC(CView,CWnd)
上述代码展开成为:
//in header file
class CView : public CWnd
{
public:
static CRuntimeClass classCView;/
virtual CRuntimeClass* GetRuntimeClass() const;
...
};
//in implementation file
static char _lpszCView[] = "CView";
CRuntimeClass CView::classCView = {
_lpszCView,sizeof(CView),0xFFFF,NULL,&CWnd::classCWnd,NULL
};
static AFX_CLASSINIT _init_CView(&CView::classCView);
CRuntimeClass *CView::GetRuntimeClass()const
{
return &CView::classCView;
}
//程序中只需要简简单单的两个宏DECLARE_DYNAMIC(Cxxx)和IMPLEMENT_DYNAMIC(Cxxx,Cxxxbase),就完成了建构数据并加入链表的工作。
使用这组宏的类必须要有基类,但是CObject没有基类怎么处理呢?
链表的头,总是要特别费心处理,不能够套用一般的链表行为方式。我们的类根源CObject,不能套用现成的宏
其中DECLARE_NYNAMIC和IMPLEMENT_DYNAMIC,必须特别设计如下:
//in header file
class CObject
{
public:
virtual CRuntimeClass* GetRuntimeClass()const;
...
public:
static CRuntimeClass classObject;
};
//in implementation file
static char szCObject[] = "CObject";
struct CRuntimeClass CObject::classObject = {
szCObject,sizeof(CObject),0xffff,NULL,NULL};
static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
CRuntimeClass* CObject::GetRuntimeClass()const
{
return &CObject::classCObject;
}
//做了一个让CObject的m_pBaseClass指向为空的操作,这样整个“类别型录”链表的头部就形成了。
在CObject中做以下实现就可以使用RTTI的IsKindOf功能了:
BOOL CObject::IsKindOf(const CRuntimeClass* pClass)const
{
//simple SI case
CRuntimeClass* pClassThis = GetRuntimeClass();
return pClassThis->IsDerivedFrom(pClass);
}
BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass)const
{
//Simple SI case
const CRuntimeClass* pClassThis = this;
while(pClassThis != NULL)
{
if(pClassThis == pBaseClass)
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
2.为了实现动态创建功能,增加了DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE
#define DECLARE_DYNCREATE(class_name) "
DECLARE_DYNAMIC(class_name) "
static CObject* PASCAL CreateObject();
#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)
//通过把CreateObject方法的指针保存到CRuntimeClass中,然后使用CRuntimeClass便可实现动态创建对象。