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宏来实现。