1. 核心类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;
CObject* CreateObject(); static CRuntimeClass* PASCAL Load();
// CRuntimeClass objects linked together in simple list static CRuntimeClass* pFirstClass; // start of class list CRuntimeClass* m_pNextClass; // linked list of registered classes };
CRuntimeClass的关键字段:
1.1 m_lpszClassName: 类型名,所有实现rtti的类都要通过这个名称来创建. 命名规范为 _lpsz + 类名 如要创建类CObject,则对应的CRuntimeClass类为classCObject,classCObject的m_lpszClassName字段值为szCObject。
1.2 m_pfnCreateObject: 函数指针, 其申明为: CObject *(PASCAL* m_pfnCreateObject)(); 1.3 CreateObject()函数 其申明为: CObject* CreateObject();
1.4 pFirstClass 和 m_pNextClass 其申明为: static CRuntimeClass* pFirstClass; // start of class list CRuntimeClass* m_pNextClass;
注意: pFirstClass被申明为static,因为这个属性在编译的时候就要被赋初值 而m_pNextClass是非static的
CRuntimeClass通过这2个属性来构建出所有支持的类型链表。
------------------------- 举例 --------------------------------- 假如要创建一个类Ca,必须从CObject继承. 2. 在类Ca中加入一个CRuntimeClass类型的静态成员变量classCa (变量名称必须依据命名规范 class + 类名): public: static CRuntimeClass classCa ;
3. 把classCa成员变量的指针加入到CRuntime的类链表中(该类链表中的元素都从CRuntime继承)。 4. 初始化静态变量classCa: CRuntimeClass Ca::classCa = { "_lpszCa", sizeof(Ca), 0xFFFF, Ca::CreateObject, //函数指针, classCa的m_pfnCreateObject成员变量的值被指定为Ca::CreateObject。 // NULL 表示Ca是虚类 (&CObject::classCObject), 0 }; 5. 在CRuntimeClass中定义一个Load函数,其功能是根据参数在CRuntimeClass的类链表中查找是否存在这个类,如果存在,则返回这个类指针 CRuntimeClass* * CRuntimeClass::Load( char szClassName ){ CRuntimeClass* pClass; for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass) { if (strcmp(szClassName, pClass->m_lpszClassName) == 0) return pClass; } //类链表中没有这个类 return NULL; } 6. 调用Load函数,并把参数设为"classCa" CRuntimeClass* pClassRef; pClassRef = CRuntimeClass::Load(); //本例得到得是Ca中静态成员变量classCa 得指针。 然后调用classCa的 CreateObject()函数 CObject* pOb; pOb = pClassRef->CreateObject(); pOb->doSomething();
//----------------------------------------------------- 核心宏: 所有的类型申明和定义都是通过宏来实现的,无法通过函数来实现,因为所有的类型必须在编译的时候就确定下来。 这些宏可以分为2类:
1. 构建CRuntimeClass中类型链表的宏
1.1 DECLARE_DYNAMIC(class_name):
#define DECLARE_DYNAMIC(class_name) \ public: \ static CRuntimeClass class##class_name; \ virtual CRuntimeClass* GetRuntimeClass() const;
1.2 IMPLEMENT_DYNAMIC(class_name, base_class_name)
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \ _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
2. 通过类型名称创建类的宏
2.1 DECLARE_DYNCREATE(class_name)
#define DECLARE_DYNCREATE(class_name) \ DECLARE_DYNAMIC(class_name) \ static CObject* PASCAL CreateObject();
2.2 IMPLEMENT_DYNCREATE(class_name, base_class_name)
#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)
注意:第二类宏(通过类型名称创建类的宏)包含了对应的第一类宏(declare和 implement),所以,如果用了第二类宏,就不需要再用第一类宏了。 也即: 如果用了第二类宏来申明和实现类的动态创建,则自动完成了动态类链表的创建。
但是,如果某些动态类是不能创建的,只能申明,则只要使用第一类宏。比如一下虚类(如CObject(它是很多具体类的父类)),在CRuntimeClass的类链表中存在这个类,但是不能创建它,因为对它没有使用第二类宏(即它没有CreateObject函数)。
3. 另一个重要的宏_IMPLEMENT_RUNTIMECLASS 在IMPLEMENT_DYNAMIC和IMPLEMENT_DYNCREATE宏中,都调用了宏_IMPLEMENT_RUNTIMECLASS,但是对于最好一个参数(表示createobject的函数指针)使用了不同的参数值(). IMPLEMENT_DYNAMIC 使用NULL, IMPLEMENT_DYNCREATE宏使用class_name::CreateObject. NULL 表示没有createobject函数的实现, 也表示了对应的类是一个虚类。 _IMPLEMENT_RUNTIMECLASS宏的定义(很负责,其实它才是真正的核心宏): #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 }; \ static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \ CRuntimeClass* class_name::GetRuntimeClass() const \ { return &class_name::class##class_name; } \
其中含有一个 静态的类(structure)AFX_CLASSINIT的实例对象,由这个对象的构造函数来把类型链表串起来. AFX_CLASSINIT的申明和定义如下:
struct AFX_CLASSINIT { AFX_CLASSINIT(CRuntimeClass* pNewClass); };
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass) { pNewClass->m_pNextClass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pNewClass; }
//----------------------------------------------------- 重点总结: 功能是通过宏来实现的 基本上所有的变量都是static, 要定义好类的命名规范,这是宏能正确达到预定功能的前提。
//------------------------------------------------------

|