在C++中可以给基类的指针或者引用赋一个子类的对象,怎么知道这些基类的指针或者引用的实际类型呢?这就需要运行时类型识别(RTTI)。有两个操作符提供RTTI:typeid和dynamic_cast。对于带虚函数的类,运行时执行RTTI操作符,对于其它类型,编译时执行RTTI操作符。
1.dynamic_cast 基类的指针或者引用可能指向一个子类的对象,有时候想使用子类新增的函数而不是基类定义的共有的函数,这时候就需要通过dynamic_cast把这个指针或者引用转换成子类的指针或者引用。 对于指针:如果要转换的目标类型不是该指针指向的实际类型,则失败,返回为0.对于引用:失败时抛出一个bad_cast异常。 2.typeid操作符 有时候需要知道表达式到底是什么类型。比如,一个基类的指针或者引用,在运行时可能指向基类的对象,也可能指向子类的对象,那么在运行的某一时刻到底是哪个具体的类型呢?这样的问题可以通过typeid操作符来解决。 typeid(e); e可以为表达式,类的名称,或者类型的名称。 当e是定义了至少一个虚函数的类的对象时,才在运行时计算类型。 typeid操作符的结果是名为type_info的标准库类的对象引用。要使用type_info需要包含相应的头文件。 classname *p; if(typeid(*p) == typeid(classname)) {...} 如果是typeid(p),那么Testing a pointer returns the static compile-time type of the pointer.没有测试,不知道type of the pointer的准确含义。 3.使用RTTI的一个例子(来自C++ primer) 任务:测试两个对象给定的数据成员集是否相等。子类可以增加数据,所以比较时应该考虑到这些增加的数据成员。 方案1: bool operator == (const base&, const base&); bool operator == (const base&, const derived&); bool operator == (const derived&, const base&); bool operator == (const derived&, const derived&); 两个类4个函数,3个类9个。。。这种方案不可行 可行的方案: class base{ friend bool operator == (const base&, const base&); protected: virtual bool equal (const base&) const; } class derived:{ friend bool operator == (const base&, const base&); private: virtual bool equal (const base&) const; } bool operator == (const base& lhs, const base& rhs) { return typeid(lhs) == typeid(rhs) && lhs.equal(rhs); //先比较是不是同一个类型,不是表达式直接返回false, //是同一类型,则调用equal,equal是一个虚函数,会根据lhs的类型调用相应的equal //如果调用子类的,那么要先把rhs动态转换一下 //如果是基类的则不用 //这种方法扩展性好,无论多少个子类,先用类型比较保证equal调用时,lhs和rhs的类型是一样的 //所以equal中,只要把rhs动态转换成和lhs相同的类型,然后再比较即可 } bool derived::equal(const base &rhs) const { if(const derived * dp = dynamic_cast<const derived*> (&rhs)) {...} else return false; } bool base::equal(const base & rhs) const { ... }