C++ RTTI,dynamic_cast,typeid 看这一篇就够了
RITTI :运行时类型识别
通过运行时类型识别,程序能够使用基类的指针或者引用,来检查这些指针或者引用所值得对象的实际派生类型。
RTTI可以看做系统提供给我们的一种功能。通过两个运算符体现。
- dynamic_cast:能够将基类的指针或者引用安全的转换为派生类的指针或者引用。
- typeid运算符:返回指针或者引用所指向的实际类型。
- 补充:RTTI的两个运算符想要正常工作,基类中至少有一个虚函数。不然这两个运算符工作的结果和我们的预测不一致。只有虚函数的存在,这两个运算符才会使用指针或者引用所绑定的对象的动态类型。
- 父类虚函数,子类重写,父类指针调用该函数的时候,会执行子类的函数,如果不是虚函数,则不能调用。
dynamic_cast运算符
如果该运算符能够转换成功,说明这个指针实际上是要转换到的那个类型。dynamic_cast 会做安全检查。dynamic_cast:转换成子类或者基类类型。
//指针类型
Human* ph = new Man;//Human 里面必须有虚函数
Man* p1 = (Man*)ph;//c语言强制类型转换。不安全
Man* p2 = dynamic_cast<Man*> (ph);//注意括号
if(p2 != NULL)//如果成功,p2会等于NULL
p2->testfunc();
else
{
//转换失败
}
对于引用,如果dynamic_cast转换失败,系统会抛出一个bad_casty异常。try{}…catch(){}捕获。
Human* ph = new Man;//Human 里面必须有虚函数
Human& q = *ph;
try
{
Man men = dynamic_cast<Man&>(q);//转成功,执行
men.testfunc();
}
catch (bad_cast)//转换失败进入
{
cout << "转换失败" << endl;
}
typeid运算符
typeid(类型,指针,引用),typeid(表达式)
拿到对象的信息,返回一个 常量对象的引用,是一个标准库类型typeid_info(类,类型)。
Human* ph = new Man;//Human 里面必须有虚函数
Human& q = *ph;
cout << typeid(*ph).name()<<endl;//class Man
cout << typeid(q).name() << endl;//class Man
cout << typeid(12).name() << endl;
cout << typeid(1.2).name() << endl;
cout << typeid("123").name() << endl;
cout << typeid(1+3.5).name() << endl;
常用用途:比较两个指针是否指向同一个类型。
Human* ph = new Man;//Human 里面必须有虚函数
Human* ph2 = new Women;
if (typeid(ph) == typeid(ph2))//直接用指针名比价,看定义类型,不符合我们要求
{
cout << "ph 和 ph2 是同一种类型" << endl;
}
//比较的时候,想比较的是new的是不是同一个类。
if (typeid(*ph) != typeid(*ph2))//用指针指向的对象(*p),看new,一定不要忘记*
{
cout << "*ph 和 *ph2 不是同一种类型" << endl;
}
if (typeid(*ph) == typeid(Man))//可以直接typeid(类名)
{
cout << "ph指向Man" << endl;
}
基类必须要有虚函数,否则条件不成立
只有基类中有虚函数时,编译器才会对typeid()中的表达式求值,如果基类中不含虚函数,则typeid()返回表达式的静态类型(定义时的类型)。编译器就无需对表达式求值。
type_info类
typeid会返回一个 常量对象的引用,这个常量对象时一个标准库类型,type_info(类,类型)。
常用函数:
1. .name()
Human* ph = new Man;//Human 里面必须有虚函数
const type_info& tp = typeid(*ph);
cout << tp.name() << endl;//class Man
2. ==, !=
Human* ph = new Man;//Human 里面必须有虚函数
const type_info& tp = typeid(*ph);
Human* ph2 = new Man;//Human 里面必须有虚函数
const type_info& tp2 = typeid(*ph2);
if (tp2 == tp)//相同,进入
{
cout << "类型形同" << endl;
}
Human* ph3 = new Women;//Human 里面必须有虚函数
const type_info& tp3 = typeid(*ph3);
if (tp3 == tp)//不相同,无法进入
{
cout << "类型形同" << endl;
}
虚函数表
在c++中,如果类中含有虚函数表。编译器就会对该类产生一个虚函数表。
- 表里有很多项,每一项都是一个指针,每个指针指向的是这个类的各个虚函数的入口地址。
- 虚函数表项里,第一个表项很特殊,指向的不是虚函数的入口地址,他指向的是类所关联的tpye_info对象。
Human* ph = new Man;//Human 里面必须有虚函数
const type_info& tp = typeid(*ph);
//ph对象中有一个看不见的指针,这个指针指向这个对象所在的类(Man)里的虚函数表。