zoukankan      html  css  js  c++  java
  • 动态类型识别&动态创建

    以下大部分内容摘自《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! 
    ";
            
            // 返回类的信息,要从CRuntimeClass中提取
            CRuntimeClass* pClass = pMyObject->GetRuntimeClass();
            cout << pClass->m_lpszClassName << "
    ";   // 打印出"CPerson"
            cout << pClass->m_nObjectSize << "
    ";       // 打印出"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 << "创建成功!
    ";
            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 << " 创建成功!
    ";
            delete pObject;
        }
    }

  • 相关阅读:
    Java8新特性之Collectors
    java日期的运用(DateUtils工具类)
    正则表达式30分钟入门教程
    一篇非常好的Spring教程
    结合实际需求,在webapi内利用WebSocket建立单向的消息推送平台,让A页面和服务端建立WebSocket连接,让其他页面可以及时给A页面推送消息
    关于企业微信对接内部应用开发,access_token的管理机制和业务接口调用项目实战的八个要点
    企业微信使用DevTools但显示为空白,解决方法
    16.刚体碰撞事件监测与处理
    15.碰撞体
    14.刚体组件Rigidbody
  • 原文地址:https://www.cnblogs.com/qiangua/p/3704890.html
Copyright © 2011-2022 走看看