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*
upcastclass 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);
这种转换很普通,看不出什么特别之处,不管是直接父类还是间接父类,都应该是当然而。 downcastclass 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); }