RTTI:Run Time Type Identification运行时类型识别
通过运行时类型识别,程序能够使用基类指针或者引用来检查这些指针或者引用所指向的对象的实际派生类型。
RTTI我们可以把它看成系统提供给我们的一种能力,这种能力是通过两个运算符来体现的:
1、dynamic_cast运算符:能够将基类的指针或引用安全的转换为派生类的引用或者指针。
2、typeid 运算符:返回指针或者引用所指对象的实际类型。
要想让RTTI的两个运算符可以正常工作,那么基类中至少必须要有一个虚函数,不然的话这两个运算符工作的结果就会跟我们预测的不一样,因为只有虚函数的存在,这两个运算符才会使用指针或者引用所绑定的动态类型。
//Human.h
class Human{
public:
Human();
virtual void eat() = 0;
};
//Human.cpp
Human::Human(){
cout << "父类Human" << endl;
}
//---------------------------------------------------------------------
//Man.h
class Man: public Human{
public:
Man();
void eat();
void eat();
};
//Man.cpp
Man::Man(){
cout << "子类Man" << endl;
}
void Man::eat(){
cout << "Man:eat" << endl;
}
int main(){
Human *phuman = new Man();
phuman -> eat(); //父类指针无法调用子类中的非虚函数
Man *pman = dynamic_cast<Man *>(phuman);
if (pman != nullptr){
cout << "转换成功" << endl;
}else{
cout << "phuman不是Men类型" << endl;
}
Human &q = *phuman;
try{
Men &manbm = dynamic_cast<Man &>(q)
cout << "phuman实际是一个Man类型" << endl;
}catch(std::bad_cast)
{
cout << "phuman实际不是一个Man类型" << endl;
}
}
dynamic_cast:这个运算符会帮我们做安全检查,如果该运算符能够转换成功,说明这个指针实际上是要转换到的那个类型。
对于引用,如果dynamic_cast转换失败,则系统会抛出一个std::bad_cast异常。
typeid运算符
一般 typeid(类型);也可能typeid(表达式):用来拿到对象的类型信息(指针,引用);typeid会返回一个常量对象的引用,这个常量对象是一个标准库类型 type_info(类)
Human *phuman = new Man;
Human &q = *phuman;
cout << typeid(phuman).name() << endl;
cout << typeid(q).name() << endl;
Human *phuman = new Man;
Human *phuman2 = new Woman;
if(typeid(phuman) == typeid(phuman2)){
cout << "same" << endl; //phuman与phuman2是同一种类型,都是Human *
}
if(typeid(*phuman) == typeid(*phuman2)){
cout << "same" << endl; //*phuman与*phuman2不是同一种类型
}
if(typeid(*phuman) == typeid(Man)){
cout << "same" << endl; //*phuman与Man是同一种类型
}
比较对象时,看的是new出来的是哪个对象,或者该指针指向的是那个对象, 和定义该指针时定义的类型没有关系。注意不要想上式一样写错。
只有在基类有虚函数时,系统才会有RTTI动态识别机制,对typeid()中的表达式求值,否则上面3式就会不成立,否则返回的是表达式的静态类型(定义时的类型)。
既然是定义的类型,编译器就不需要对表达式求值也能知道表达式的类型。
type_info类
typeid()就会返回一个 常量的对象引用,这个常量对象 是一个标准库类型 type_info(类/类类型)。
.name:名字,返回一个c风格的字符串。
虚函数表:
C++中,如果类里含有虚函数。那么编译器就会对该类产生一个虚函数表。虚函数表里有很多项,每一项都是一个指针。每个指针指向的是这个类里各个虚函数的入口地址。
虚函数表里的第一项很特殊,它指向的不是虚函数的入口地址,它指向的实际上是这个类所关联的type_info对象。
phuman对象里有一个我们看不见的指针,这个指针指向的就是这个对象所在类Man里的虚函数表。