一、RTTI运行时类型识别
1. 作用
作用:通过运行时类型识别,程序能够使用基类指针或引用来检查这些指针或引用所指的对象的实际派生类对象。(包含两个运算符dynamic_cast、typeid)
注意:要想两个运算符能后正常使用,那么基类中至少要有一个虚函数
2. dynamic_cast运算符
能够将基类的指针或引用安全的转换成派生类的指针或引用。(可以做安全类型检查)
将基类指针转换成派生类指针 代码演示:
Human* p = new Man;
p->eat(); //基类的虚函数,子类都有重写
//Man* q = (Man*)p; //C语言风格强制类型转换
//q->Func(); //能够正常调用 Man类的成员函数
Man* q = dynamic_cast<Man*>(p);
if (q != nullptr) //判断是否转换成功
{
//转换成功
q->Func(); //就能调用派生类里面的成员函数
}
else
{
cout << "转换失败" << endl;
}
将基类引用转换成派生类引用,代码演示:
Human* p = new Man;
Human& human = *p;
try
{
Woman& woman = dynamic_cast<Woman&>(human); //转换失败会抛出异常
Man& man = dynamic_cast<Man&>(human); //转换成功
man.Func(); //可以正常调用派生类的成员函数,安全的
}
catch (const std::exception& e)
{
cout << e.what() << endl; //转换失败时抛出异常 bad_cast
}
3. typeid运算符
返回指针或引用所指对象的实际类型。
基本用法:
typeid(类型[指针、引用]); typeid(表达式)
拿到对象类型信息,typeid就会返回一个常量对象的引用,这个常量对象是一个标准库类型 type_info(类类型)
Human* p = new Man;
Human& human = *p;
cout << typeid(p).name() << endl;
cout << typeid(human).name() << endl;
char buf[10] = { 10,25 };
cout << typeid(buf).name() << endl;
cout << typeid(10).name() << endl;
cout << typeid("asdas").name() << endl;
typeid是C++的关键字之一,等同于sizeof这类的操作符。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用。
如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
- 当typeid操作符的操作数是不带有虚函数的类类型时,typeid操作符会指出操作数的类型,而不是底层对象的类型。
- 如果typeid操作符的操作数是至少包含一个虚拟函数的类类型时,并且该表达式是一个基类的引用,则typeid操作符指出底层对象的派生类类型。
4. 虚函数表
C++ 中,如果类中函数有虚函数。编译器就会产生一个虚函数表。虚函数表里有很多项,每一项都是一个指针。每个指针指向的是这个类里各个虚函数的入口地址。
虚函数表项里,第一个表项很特殊,它指向的不是虚函数的入口地址,它指向的实际上是咱们这个类所关联的type_info对象。