通过运行时类型识别(RTTI),程序能够使用基类的指针或引用来检索这些指针或引用所指向对象的实际派生类型
通过下面两个操作符提供RTTI( dynamic_cast 与typeid):
一、dynamic_cast
#include <iostream>
class base {
public:
virtual ~base() {
}
virtual void isWhat() {
std::cout << "base" << std::endl;
}
};
class derived: public base {
public:
void isWhat() {
std::cout << "derived" << std::endl;
}
};
int main() {
base* bPtr = new derived();
base& bRef = *bPtr;
/*对于指针,如果转化失败,则将指针置为NULL*/
if (derived* derPtr = dynamic_cast<derived*>(bPtr)) {
derPtr->isWhat();
}
else {
/* derPtr == NULL*/
}
/*对于引用类型,因为没有NULL,所以直接抛出bad_cast异常*/
try {
derived& derRef = dynamic_cast<derived&>(bRef);
derRef.isWhat();
}
catch (std::bad_cast& e) {
/* throw a bad_cast exception*/
}
return 0;
}
二、typeid
int main() {
base* bPtr = new derived();
base& bRef = *bPtr;
if (typeid(*bPtr) == typeid(derived)) { // is "*bPtr" not "bPtr"
bPtr->isWhat();
}
if (typeid(bRef) == typeid(*bPtr)) {
bRef.isWhat();
}
return 0;
}
注意:对于没有虚函数的类,typeid返回的是指针的静态类型。
三、type_info
与typeid相关的一个概念,是type_info类。创建type_info类唯一对象的方法是使用typeid操作符。
至少提供了4个函数:t1==t2, t1!=t2, t1.name(), t1.before(t2)。
int main() {
base* bPtr = new derived();
base& bRef = *bPtr;
if (typeid(*bPtr) == typeid(derived)) { // is "*bPtr" not "bPtr"
bPtr->isWhat();
}
if (typeid(bRef) == typeid(*bPtr)) {
bRef.isWhat();
}
std::cout<<typeid(*bPtr).name()<<std::endl;
base *ptr = new base();
std::cout << typeid(*bPtr).before(typeid(*ptr)) << std::endl; // false
std::cout << typeid(*ptr).before(typeid(*bPtr)) << std::endl; // true, 继承关系的先后顺序
return 0;
}
四、RTTI的使用
假设类Derived继承自Base,并且添加了一些其他的数据成员,我们要为这个继承派生体系定义相等操作符,但是由于基类和派生类之间的转化关系,我们很难确定比较操作符的实际类型。所以,两个所以我们需要在比较操作时,先1)确定两个操作数的类型是否相同。如果不同,直接返回假,如果相同,那么2)再比较它们的数据是否相等。
class Base {
friend bool operator==(const Base& lhs, const Base& rhs);
public:
explicit Base(int b): base_elem(b) { // explicit 只能用于类内部的构造函数的申明上面
}
virtual ~Base() {
}
private:
int base_elem;
protected:
virtual bool equal(const Base& rhs) const { // 只比较base类成员,其他不管
return rhs.base_elem == base_elem;
}
};
class Derived : public Base {
friend bool operator==(const Base& lhs, const Base& rhs);
public:
Derived(int d, int b) : derived_elem(d), Base(b) {}
virtual ~Derived() {
}
private:
int derived_elem;
protected:
virtual bool equal(const Base& rhs) const {
if (const Derived* ptr = dynamic_cast<const Derived*>(&rhs))
return this->Base::equal(*ptr) && (derived_elem == ptr->derived_elem);
else
return false;
}
};
// 简化了代码,无须再对 const Derived& 形参进行重载
bool operator == (const Base& lhs, const Base& rhs) {
return (typeid(lhs) == typeid(rhs)) && (lhs.equal(rhs));
}