zoukankan      html  css  js  c++  java
  • [转]手工实现RTTI

    运行时的动态类型检查(RTTI,Run Time Type Indentifiation)是c++中提供的一项语言机制,它主要用于判断多态对象的具体类型。      

    为什么不使用c++提供的RTTI功能      

    但c++中直接提供的RTTI存在一些缺点。首先它提供了取得类名(typeinfo中的name函数)的功能,这个功能实际上并不是RTTI必须的。很多时候我们不需要取得类的名字,而只是希望判断某对象的具体类型。而且typeinfo取得的名字还不一定是可移植的,不同编译器取得的类型名字不一定一样。      

    其次,在大多数情况下如果打开RTTI,一般来说程序中的所有多态类都会附加上RTTI信息的开销,而我们常常只需要选择其中某些类具有RTTI的功能就可以了。      

    总的来说,c++语言提供的RTTI与编译器相关,并不是可控的。因此我们有必要自己实现一份RTTI。      

    如何实现自己的RTTI? 

    首先需要知道如何为需要RTTI功能的类分配一个唯一的ID号。这个问题可以在STL的国际化对象Locale中找到答案。在Locale中定义了一个名为id的类,id类中没有任何成员,每一个facet类都有一个id类的静态对象。这样程序在初始化的时候会为每一个facet类中的静态id对象分配1byte的空间。这样某个facet类的静态id对象的地址就是该类的唯一标识符。      我们需要RTTI的类中也可以存放这样一个静态对象,其地址用于唯一标记每一个类。还有一个问题就是我们需要追溯一个类的所有父类。这样我们可以在每个静态ID对象其中保存其所有父类的静态ID对象的指针,这样可以构成了一棵和继承树相同的RTTI树。然后可以通过回溯的方法检查所有父类的ID。这样就可以实现自己的RTTI了。      

    下面是自己实现RTTI的代码: 

       /** 
         * 运行时类型信息(Run Time Type Information). 
         * 用于帮助在运行中识别对象的类型.这里不使用c++本身的RTTI 
         * 机制是因为它并不完全可移植并且不可控. 
         * 注意自己实现的RTTI最多只支持MAX_BASE_CLASS_CNOUT(8)个基类. 
         * 因此在多重继承的时候需要注意这个限制.如果真的有一个类需 
         * 要继承超过8个带RTTI功能的基类,请修改MAX_BASE_CLASS_CNOUT的值, 
         * 并为RTTI类增加新的构造函数,然后再为指定基类数目添加一个新的 
         * RTTI_X_BASE_CLASS_IMPLEMENT宏. 
         * @author songfeiyu 
         */ 
        class RTTI 
        { 
            NON_COPYABLE_DECLARE(RTTI); 
        public: 
           /** 
            * 在多重继承中可以最大继承的基类的数量 
            * @note 一般的设计不应该超过8个吧,如果真的超过建议 
            *       先检查设计是否有问题... 
            */ 
            static const size_t MAX_BASE_CLASS_CNOUT = 8; 
            /// 无基类情况下的构造函数 
            RTTI() 
                : m_baseClassCnt(0) 
            {} 
            /// 一个基类的情况 
            RTTI(const RTTI* baseClass0) 
                :m_baseClassCnt(1) 
            { 
                m_baseClass[0] = baseClass0; 
            } 
            /// 两个基类的情况 
            RTTI(const RTTI* baseClass0, const RTTI* baseClass1) 
                :m_baseClassCnt(2) 
            { 
                m_baseClass[0] = baseClass0; 
                m_baseClass[1] = baseClass1; 
            } 
            /// 三个基类的情况 
            RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2) 
                :m_baseClassCnt(3) 
            { 
                m_baseClass[0] = baseClass0; 
                m_baseClass[1] = baseClass1; 
                m_baseClass[2] = baseClass2; 
            } 
            /// 四个基类的情况 
            RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2, 
                 const RTTI* baseClass3) 
                :m_baseClassCnt(4) 
            { 
                m_baseClass[0] = baseClass0; 
                m_baseClass[1] = baseClass1; 
                m_baseClass[2] = baseClass2; 
                m_baseClass[3] = baseClass3; 
            } 
            /// 五个基类的情况 
            RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2, 
                 const RTTI* baseClass3, const RTTI* baseClass4) 
                :m_baseClassCnt(5) 
            { 
                m_baseClass[0] = baseClass0; 
                m_baseClass[1] = baseClass1; 
                m_baseClass[2] = baseClass2; 
                m_baseClass[3] = baseClass3; 
                m_baseClass[4] = baseClass4; 
            } 
            /// 六个基类的情况 
            RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2, 
                 const RTTI* baseClass3, const RTTI* baseClass4, const RTTI* baseClass5) 
                :m_baseClassCnt(6) 
            { 
                m_baseClass[0] = baseClass0; 
                m_baseClass[1] = baseClass1; 
                m_baseClass[2] = baseClass2; 
                m_baseClass[3] = baseClass3; 
                m_baseClass[4] = baseClass4; 
                m_baseClass[5] = baseClass5; 
            } 
            /// 七个基类的情况 
            RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2, 
                 const RTTI* baseClass3, const RTTI* baseClass4, const RTTI* baseClass5, 
                 const RTTI* baseClass6) 
                :m_baseClassCnt(7) 
            { 
                m_baseClass[0] = baseClass0; 
                m_baseClass[1] = baseClass1; 
                m_baseClass[2] = baseClass2; 
                m_baseClass[3] = baseClass3; 
                m_baseClass[4] = baseClass4; 
                m_baseClass[5] = baseClass5; 
                m_baseClass[6] = baseClass6; 
            } 
            /// 八个基类的情况 
            RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2, 
                 const RTTI* baseClass3, const RTTI* baseClass4, const RTTI* baseClass5, 
                 const RTTI* baseClass6, const RTTI* baseClass7) 
                :m_baseClassCnt(8) 
            { 
                m_baseClass[0] = baseClass0; 
                m_baseClass[1] = baseClass1; 
                m_baseClass[2] = baseClass2; 
                m_baseClass[3] = baseClass3; 
                m_baseClass[4] = baseClass4; 
                m_baseClass[5] = baseClass5; 
                m_baseClass[6] = baseClass6; 
                m_baseClass[7] = baseClass7; 
            } 
            /// 取得基类的个数 
            size_t GetBaseClassCnt() const { return m_baseClassCnt; } 
            ///取得第idx个基类指针 
            const RTTI* GetBaseClassRTTI(size_t idx) const { return m_baseClass[idx]; } 
            /** 
             * 判断传入的rtti指针是否与自身类型精确匹配(不检查父类). 
             */ 
            bool IsExactKindOf(const RTTI* rtti) const 
            { 
                return this == rtti; 
            } 
            /** 
             * 判断传入的rtti指针是否自身类型匹配(检查父类). 
             */ 
            bool IsKindOf(const RTTI* rtti) const 
            { 
                // 如果该对象的rtti和自身rtti地址一致,则类型匹配. 
                if(this == rtti) 
                { 
                    return true; 
                } 
                // 否则就检查所有父类. 
                for(size_t i = 0; i < rtti->GetBaseClassCnt(); ++i) 
                { 
                    //如果某个父类匹配,则返回true. 
                    if(this->IsKindOf(rtti->GetBaseClassRTTI(i))) 
                    { 
                        return true; 
                    } 
                } 
                return false; 
            } 
        private: 
            const RTTI* m_baseClass[MAX_BASE_CLASS_CNOUT];// 基类的RTTI指针 
            const size_t m_baseClassCnt;// 基类的个数 
        }; 
    
        /** 
         * 判断该对象是否与TYPE类型精确匹配(不检查父类). 
         * 用法:bool is = IsExactKindOf<TestType>(obj); 
         */ 
        template<typename TYPE, typename OBJ> 
        inline bool IsExactKindOf(OBJ* obj) 
        { 
            ASSERT_MESSAGE(obj, _T("The param obj is NULL.")); 
            return TYPE::GetStaticRTTI()->IsExactKindOf(obj->GetRTTI()); 
        } 
        template<typename TYPE, typename OBJ> 
        inline bool IsExactKindOf(const OBJ& obj) 
        { 
            ASSERT_MESSAGE(obj, _T("The param obj is NULL.")); 
            return TYPE::GetStaticRTTI()->IsExactKindOf(obj.GetRTTI()); 
        } 
        /** 
         * 判断该对象是否与TYPE类型匹配(检查父类). 
         * 用法:bool is = IsKindOf<TestType>(obj); 
         */ 
        template<typename TYPE, typename OBJ> 
        inline bool IsKindOf(OBJ* obj) 
        { 
            ASSERT_MESSAGE(obj, _T("The param obj is NULL.")); 
            return TYPE::GetStaticRTTI()->IsKindOf(obj->GetRTTI()); 
        } 
        template<typename TYPE, typename OBJ> 
        inline bool IsKindOf(const OBJ& obj) 
        { 
            return TYPE::GetStaticRTTI()->IsKindOf(obj.GetRTTI()); 
        } 
    
    /** 
    * 该宏用于放在所有RTTI对象的开始位置. 
    */ 
    #define RTTI_DECLARE / 
        public: / 
            static const RTTI* GetStaticRTTI() { return &ms_RTTI; } / 
            virtual const RTTI* GetRTTI() const { return &ms_RTTI; } / 
        private: / 
            static const RTTI ms_RTTI; 
    
    /** 
    * 这一组宏用于定义继承n个基类的RTTI对象. 
    */ 
    #define RTTI_NO_BASE_CLASS_IMPLEMENT(className) / 
        const RTTI className::ms_RTTI; 
    #define RTTI_1_BASE_CLASS_IMPLEMENT(className, baseClass0) / 
        const RTTI className::ms_RTTI(baseClass0::GetStaticRTTI()); 
    #define RTTI_2_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1) / 
        const RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), / 
            baseClass1::GetStaticRTTI()); 
    #define RTTI_3_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2) / 
        const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), / 
            baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI()); 
    #define RTTI_4_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, / 
            baseClass3) / 
        const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), / 
            baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI()); 
    #define RTTI_5_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, / 
            baseClass4) / 
        const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), / 
            baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), / 
            baseClass4::GetStaticRTTI()); 
    #define RTTI_6_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, / 
            baseClass4, baseClass5) / 
        const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), / 
            baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), / 
            baseClass4::GetStaticRTTI(), baseClass5::GetStaticRTTI()); 
    #define RTTI_7_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, / 
            baseClass4, baseClass5, baseClass6) / 
        const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), / 
            baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), / 
            baseClass4::GetStaticRTTI(), baseClass5::GetStaticRTTI(), baseClass6::GetStaticRTTI()); 
    #define RTTI_8_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, / 
            baseClass4, baseClass5, baseClass6, baseClass7) / 
        const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), / 
            baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), / 
            baseClass4::GetStaticRTTI(), baseClass5::GetStaticRTTI(), baseClass6::GetStaticRTTI(), / 
            baseClass7::GetStaticRTTI()); 

    这样只需要在需要RTTI类的声明中加上RTTI_DECLARE宏,并在实现中根据基类的数量加上对象的RTTI_X_BASE_CLASS_IMPLEMENT宏就可以了,例如:  

    .h file

      class A 
        { 
            RTTI_DECLARE; 
        public: 
            ... 
        }; 
    
        class B 
        { 
            RTTI_DECLARE; 
        public: 
            ... 
        }; 
    
        class C : public A, 
                  public B 
        { 
            RTTI_DECLARE; 
        public: 
            ... 
        };

    .cpp file:

        RTTI_NO_BASE_CLASS_IMPLEMENT(A); 
        RTTI_NO_BASE_CLASS_IMPLEMENT(B); 
        RTTI_2_BASE_CLASS_IMPLEMENT(C, A, B); 

    这样就可以对A,B,C类的对象进行运行时的RTTI判断了。 
       注意在上面RTTI对象使用了一个固定长度的数组(8个)来保存所有直接父类的RTTI对象。这里其实可以使用多态实现对任意多数目直接父类的支持,但考虑到效率以及设计上的问题,在这里做出了8个直接父类的限制。 
       应该是用不完的,因为只要需要RTTI判断的直接父类多于8个才不支持(如果不需要对某个父类的RTTI判断可以不写进RTTI_X_BASE_CLASS_IMPLEMENT宏中,这样还可以避免不需要的查找开销,这又多了一层自我控制的选择)。 

        这样就可以对A,B,C类的对象进行运行时的RTTI判断了。     注意在上面RTTI对象使用了一个固定长度的数组(8个)来保存所有直接父类的RTTI对象。这里其实可以使用多态实现对任意多数目直接父类的支持,但考虑到效率以及设计上的问题,在这里做出了8个直接父类的限制。     应该是用不完的,因为只要需要RTTI判断的直接父类多于8个才不支持(如果不需要对某个父类的RTTI判断可以不写进RTTI_X_BASE_CLASS_IMPLEMENT宏中,这样还可以避免不需要的查找开销,这又多了一层自我控制的选择)。 

  • 相关阅读:
    使用php实现权限管理模块
    在Android手机上安装linux系统
    phpexcelreader超级简单使用
    Ci框架整合smarty模板引擎
    vcastr2.0插件超级简单使用
    如何让centos6.5在vm11里上网,连接网络?
    session跨域共享解决方案
    apache的 .htaccess文件的常用配置
    webbench的详细使用
    网站的压力测试
  • 原文地址:https://www.cnblogs.com/slysky/p/3904227.html
Copyright © 2011-2022 走看看