动态类型识别&动态创建
以下大部分内容摘自《windows程序设计 第2版》 王艳平 张铮 编著
动态类型识别:在程序运行过程中,辨别对象是否属于特定类的技术。
应用举例:函数辨别参数类型、需要针对对象的类编写特定的代码。
CRuntimeClass 包含类信息(不仅包含一般的信息,还包括创建类的函数指针)
#include <iostream> #include<windows.h> using namespace std; ///////////////////////////////////////////////////// // 运行期类信息 class CObject; struct CRuntimeClass { // 属性(Attributes) LPCSTR m_lpszClassName; // 类的名称 int m_nObjectSize; // 类的大小 UINT m_wSchema; // 类的版本号 // 创建类的函数的指针 函数返回值为CObject*类型 调用规则为__stdcall // 如果你没有显式的说明调用规则的话,编译器会统一按照_cdecl来处理 // c++ 指针:http://hipercomer.blog.51cto.com/4415661/792300 CObject* (__stdcall* m_pfnCreateObject)(); CRuntimeClass* m_pBaseClass; // 其基类中CRuntimeClass结构的地址 // 操作(operations) CObject* CreateObject(); //调用m_pfnCreateObject指向的函数 BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const; // 内部实现(Implementation) CRuntimeClass* m_pNextClass; // 将所有CRuntimeClass对象用简单链表连在一起 };
如果想使所有的类都具有运行期识别和动态创建的特性,那么必须有一个类做为最顶层的类,所有的类都从此类继承。
// CObject 类 class CObject { public: //注意是个虚函数 virtual CRuntimeClass* GetRuntimeClass() const; virtual ~CObject(); // 属性(Attibutes) public: BOOL IsKindOf(const CRuntimeClass* pClass) const; // 实现(implementation) public: static const CRuntimeClass classCObject; // 标识类的静态成员 };
上面是两个类的声明,下面我们看实现:
//CRuntimeClass类实现 inline CObject::~CObject() { } // 宏定义 // RUNTIME_CLASS宏用来取得class_name类中CRuntimeClass结构的地址 #define RUNTIME_CLASS(class_name) ((CRuntimeClass*)&class_name::class##class_name) CObject* CRuntimeClass::CreateObject() { if(m_pfnCreateObject == NULL) return NULL; return (*m_pfnCreateObject)(); // 调用创建类的函数 } BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const { //this指针: http://blog.csdn.net/ugg/article/details/606396 //this指针作为一个隐含参数传递给非静态成员函数,用以指向该成员函数所属类所定义的对象。 const CRuntimeClass* pClassThis = this; while(pClassThis != NULL) { if(pClassThis == pBaseClass) // 判断标识类的CRuntimeClass的首地址是否相同 return TRUE; pClassThis = pClassThis->m_pBaseClass; } return FALSE; // 查找到了继承结构的顶层,没有一个匹配 } const struct CRuntimeClass CObject::classCObject = { "CObject"/*类名*/, sizeof(CObject)/*大小*/, 0xffff/*无版本号*/, NULL/*不支持动态创建*/, NULL/*没有基类*/, NULL}; CRuntimeClass* CObject::GetRuntimeClass() const { // 下面的语句展开后就是“return ((CRuntimeClass*)&(CObject::classCObject));” return RUNTIME_CLASS(CObject); } //CObject类的实现 BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const { CRuntimeClass* pClassThis = GetRuntimeClass(); return pClassThis->IsDerivedFrom(pClass); }
动态类型识别举例:
class CPerson : public CObject { public: virtual CRuntimeClass* GetRuntimeClass() const { return (CRuntimeClass*)&classCPerson; } static const CRuntimeClass classCPerson; }; const CRuntimeClass CPerson::classCPerson = { "CPerson", sizeof(CPerson), 0xffff, NULL, (CRuntimeClass*)&CObject::classCObject, NULL }; // 类名 大小 版本号 创建类的函数的指针 基类中CRuntimeClass结构的地址 void main() { // 父类指向子类,只能调用两者都有的函数(虚函数) // 如果父类想调用子类拥有,父类没有的函数是不可以的 // 也就是父类指向子类只能调用子类的虚函数 CObject* pMyObject = new CPerson; // 判断对象pMyObject是否属于CPerson类或者此类的派生类 if(pMyObject->IsKindOf(RUNTIME_CLASS(CPerson))) // RUNTIME_CLASS(CPerson)宏被展开后相当于((CRuntimeClass*)&CPerson::classCPerson) { CPerson* pMyPerson = (CPerson*)pMyObject; cout << "a CPerson Object! \n"; // 返回类的信息,要从CRuntimeClass中提取 CRuntimeClass* pClass = pMyObject->GetRuntimeClass(); cout << pClass->m_lpszClassName << "\n"; // 打印出"CPerson" cout << pClass->m_nObjectSize << "\n"; // 打印出"4" x64为"8" delete pMyPerson; } else { delete pMyObject; } }
动态创建举例:
//声明 class CPerson : public CObject { public: virtual CRuntimeClass* GetRuntimeClass() const { return (CRuntimeClass*)&classCPerson; } static const CRuntimeClass classCPerson; static CObject* __stdcall CreateObject() { return new CPerson; } }; //实现 const CRuntimeClass CPerson::classCPerson = { "CPerson", sizeof(CPerson), 0xffff, &CPerson::CreateObject/*添加到这里*/, (CRuntimeClass*)&CObject::classCObject, NULL }; // 类名 大小 版本号 创建类的函数的指针 基类中CRuntimeClass结构的地址 void main() { // 取得CPerson类中CRuntimeClass结构记录的信息 // 在实际应用中,我们一般从磁盘上取得这一信息, // 从而在代码中没有给出类名的情况下创建该类的对象 CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson); // 取得了pRuntimeClass指针,不用知道类的名字就可以创建该类 CObject* pObject = pRuntimeClass->CreateObject(); if(pObject != NULL && pObject->IsKindOf(RUNTIME_CLASS(CPerson))) { cout << "创建成功!\n"; delete pObject; } }
MFC对它们进行“优化”,使用了看起来很恶心的宏:
//以下都采用了多行宏定义 // 支持动态类型识别的宏 //声明 #define DECLARE_DYNAMIC(class_name) \ public: \ static const CRuntimeClass class##class_name; \ virtual CRuntimeClass* GetRuntimeClass() const; //实现 #define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \ const CRuntimeClass class_name::class##class_name = { \ #class_name, sizeof(class class_name), wSchema, pfnNew, \ RUNTIME_CLASS(base_class_name), NULL }; \ CRuntimeClass* class_name::GetRuntimeClass() const \ { return RUNTIME_CLASS(class_name); } \ //运行期识别功能只需要类名与基类名即可 #define IMPLEMENT_DYNAMIC(class_name, base_class_name) \ IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL) // 支持动态创建的宏 //声明 #define DECLARE_DYNCREATE(class_name) \ DECLARE_DYNAMIC(class_name) \ static CObject* __stdcall CreateObject(); //实现 #define IMPLEMENT_DYNCREATE(class_name, base_class_name) \ CObject* __stdcall class_name::CreateObject() \ { return new class_name; } \ IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \ class_name::CreateObject)
动态创建的等价代码:
// 等价代码: class CPerson : public CObject { DECLARE_DYNCREATE(CPerson) //声明 }; IMPLEMENT_DYNCREATE(CPerson, CObject) //实现 void main() // main函数里的代码没有变化 { CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson); CObject* pObject = pRuntimeClass->CreateObject(); if(pObject != NULL && pObject->IsKindOf(RUNTIME_CLASS(CPerson))) { cout << " 创建成功!\n"; delete pObject; } }