首页 > 代码库 > 动态类型识别&动态创建

动态类型识别&动态创建

以下大部分内容摘自《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;
    }
}