RTTI c++

    技术2022-05-19  22

    RTTI: Run-Time Type Identification,就是运行时类型识别。这个功能在C++中早就有了。只不过,大家都不用,没有怎么关注过。在C#和JAVA中可能应用比较多吧。

    RTTI程序可以使用基类的指针或引用来检查所指向对象的实际派生类,它提供了一个机制可以在程序运行中判断对象的类型。在对于不同的对象有不同的操作的要求有很大的帮助。但,C++中的rtti几乎完全被否定。在刚刚发布的GOOGLE C++ CODE GUIDE中也明确指出不用RTTI。这和OO的开闭原则有冲突,而且RTTI特性完全可以用多态来实现。另外如果打开RTTI特性,还会在代码中增加一些分量。这里只是探讨一下RTTI的一般机制。

    C++中提供两个操作符来表示RTTI:dynamic_cast和typeid。

     

    dynamic_cast实现在类型间的转换。主要有三种应用 upcast, downcast和void*

    upcast

    class A{};

    class B : public A {};

    class C: public B {};

    C* pc = new C;

    B* pb = new B;

    A* pa = dynamic_cast(pc);

    pa = dynamic_cast(pb);

    这种转换很普通,看不出什么特别之处,不管是直接父类还是间接父类,都应该是当然而。 downcast

    class A{void virtual f()};

    class C : public A{};

    A* pa = new A;

    A* pc = new C;

    C* pac = dynamic_cast<C*>(pa);

    C* pcc = dynamic_cast<C*>(pc);

    这里,pac就是零值,dynamic_cast没有转换成功会返回0,而pcc就是C*的指针指向一个C对象。

    注意这里需要有虚函数

    void*

    class D {void virtual f()}

    class E {void virtual f()}

    D* pd = new D;

    E* pe = new E;

    void* pv = dynamic_cast<void*>(pd);

    pv = dynamic_cast<void*>(pe);

    这两个类是没有继承关系的,但都相同的虚函数表,所以可以转换成VOID*,并且一起管理。

    typeid操作符返回type_info&

    说明参数的类型信息。用法:

    typeid(1.0f);

    typeid(true);

    A a;

    typeid(A); typeid(a); typeid(&a);

     

    type_info描述类型信息,其实这些东西都是编译要用到的,这里只是保留下来了。那么,不同的编译器对于这些信息的保留或实现会有不一样。但基本上的信息是相同的。VC里的实现:

    class type_info { public: virtual ~type_info(); _CRTIMP_PURE bool __CLR_OR_THIS_CALL operator==(const type_info& rhs) const; _CRTIMP_PURE bool __CLR_OR_THIS_CALL operator!=(const type_info& rhs) const; _CRTIMP_PURE int __CLR_OR_THIS_CALL before(const type_info& rhs) const; _CRTIMP_PURE const char* __CLR_OR_THIS_CALL name(__type_info_node* __ptype_info_node = &__type_info_root_node) const; _CRTIMP_PURE const char* __CLR_OR_THIS_CALL raw_name() const; private: void *_m_data; char _m_d_name[1]; __CLR_OR_THIS_CALL type_info(const type_info& rhs); type_info& __CLR_OR_THIS_CALL operator=(const type_info& rhs); _CRTIMP_PURE static const char *__CLRCALL_OR_CDECL _Name_base(const type_info *,__type_info_node* __ptype_info_node); _CRTIMP_PURE static void __CLRCALL_OR_CDECL _Type_info_dtor(type_info *); };

     

    也就是说每个类都会有这样的一些信息,如果我们不用C++提供的这一套机制,完全可以自己实现自定义的RTTI,这样就可以只对有限的几个类用RTTI,其它都不用。

     

    MFC的实现

    在MFC中struct CRuntimeClass结构来实现rtti。

     

    struct CRuntimeClass

    {

    LPCSTR m_lpszClassName;

    int m_nObjectSize;

    UINT m_wSchema;

    CRuntimeClass* m_pBaseClass;

    CRuntimeClass* m_pNextClass;

    }

     

    然后用两个宏,加到了类里。

    DECLARE_DYNAMIC(class_name)

    IMPLEMENT_DYNAMIC(class_name)

     

    一个应用RTTI的例子

    你可以在C++prime中找到。

    两个类,有继承关系,要实现对象之间的比较,但对象之间的比较并不是所有数据的比较,是全部数据的一个子集。

    class Base

    {... forBase; // member variable}

    class Derived: public Base

    {... forDerived; // member variable}

     

    这样可能需要4个函数才能实现

    bool operator==(const Base&, const Base&)bool operator==(const Derived&, const Derived&)bool operator==(const Derived&, const Base&);bool operator==(const Base&, const Derived&);

     

    如果是三层的,那可能要8个函数才能完成。 

    但用了rtti情况就不同了。

     

     class Base { friend bool operator==(const Base&, const Base&); public: Base() : m_forBase(0){}; void setBaseValue(int fb) { m_forBase = fb; } protected: virtual bool equal(const Base& rhs) const { return m_forBase == rhs.m_forBase; } private: int m_forBase; }; class Derived : public Base { friend bool operator==(const Base&, const Base&); public: Derived() : m_forDerived(0){}; void setDerivedValue(int fd) { m_forDerived = fd; } private: bool equal(const Base& rhs) const { if (const Derived* dp = dynamic_cast<const Derived*>(&rhs)) { return (m_forDerived == dp->m_forDerived); } else return false; }; int m_forDerived; }; bool operator==(const Base& lhs, const Base& rhs) { std::cout << typeid(lhs).name() << typeid(rhs).name() << std::endl; return lhs.equal(rhs); }

     

     


    最新回复(0)