RTTI
run time type identification 运行时类型识别
作用是:通过运行时类型识别,程序能够使用基类的指针或者引用来检查这些指针或者引用所指向的对象的时机派生类别。
提供了 dynamic_cast运算符 和 typeid 运算符 让user 来做这个事情
dynamic_cast运算符:
能够让父类指针安全的指向一个子类.如果转换不成功,会返回null
//如果dynamic_cast 处理的是引用。使用try catch处理,在对于引用 转换的时候失败的时候,会有std::bad_cast error
Child31 * child311 = dynamic_cast<Child31 *>(pa);
Child31 & pa33 = dynamic_cast<Child31 &>(pa22);
void main() {
Parent3 *pa = new Child31(20,"child31",89.9,40,"parent3",80.9);
Parent3 & qa = *pa;//用父类的指针的* 得到父类的引用。但是实际上开发者是知道*pa指向的是一个child的。
//假设当前的需求就是我们使用子类自己的方法 -》 child31publiceat,应该怎么做呢?
//qa.child31publiceat();目前是不行的
//C语言的做法是强行转换
Child31 & qchild31 = (Child31&)*pa;
qchild31.child31publiceat();
//执行结果为:
//Parent3 构造方法被执行
// Child31构造方法执行
// Child31 自己的 public 方法执行
cout << "-------分割线-------" << endl;
//那么C语言风格的强行转换既然能处理这个问题,为什么C++还要发明一个呢?
//这是因为这玩意不安全,我们想转啥就转啥,例如转成Teacher9,但是我们知道这玩意肯定不是Teacher9呀,一旦使用就会有不可预知的事情发生,甚至有可能是run time exception
//Teacher9 & qchild311111 = (Teacher9&)*pa;//也能这么转,build pass
//qchild311111.printTeacher9();//结果是这:address = 000002CC26026200 age = 691174864 name =
//dynamic_cast 运算符,能够让父类指针或者父类引用安全的指向一个子类.如果转换不成功,会返回null
Child31 * child311 = dynamic_cast<Child31 *>(pa);
if (nullptr == child311 || NULL == child311) {
cout << "转换不成功" << endl;
}
else {
cout << "转换成功" << endl;
child311->child31publiceat();
}
//dynamic_cast的好处,如果转换不成功,则为 null
Teacher9 * child4 = dynamic_cast<Teacher9 *>(pa);
if (nullptr == child4 || NULL == child4) {
cout << "转换不成功..." << endl;
}
else {
cout << "转换成功..." << endl;
child311->child31publiceat();
}
//如果dynamic_cast 处理的是引用应该如何处理呢?使用try catch处理,在对于引用 转换的时候失败的时候,会有std::bad_cast error
Parent3 *pa11 = new Child31(20, "child31", 89.9, 40, "parent3", 80.9);
Parent3 & pa22 = *pa11;
try {
cout << "转换success 。。。。。" << endl;
Child31 & pa33 = dynamic_cast<Child31 &>(pa22);
pa33.child31publiceat();
}
catch (std::bad_cast) {
cout << "转换失败.....bad_cast" << endl;
}
typeid 运算符:
返回指针或者引用所指向对象的实际类型。
cout << "----------" << endl;
Parent3* pa66 = new Child31(20, "child31", 89.9, 40, "parent3", 80.9);
//Parent3*是类型,pa66是变量名,因此typeid(pa66).name()是
cout << typeid(pa66).name() << endl; //注意这里结果:Parent3 * __ptr64
// *pa66 是将pa66指针指向的 那部分取出来,通过typeid求,那当然是 child31了
cout<<typeid(*pa66).name()<<endl; //注意这里结果:class Child31
cout << "-----111-----" << endl;
//typeid的返回值是: type_info的一个常量引用
const type_info &a = typeid(*pa66);
cout << "-----222-----" << endl;
//typeid运算符的用法如下:
Parent3* pa77 = new Child31(120, "child31", 189.9, 140, "parent3", 8220.9);
Parent3* pa88 = new Child32(220, "child32", 289.9, 420, "parent3", 8110.9);
if (typeid(*pa66) == typeid(*pa77)) {
cout << "typeid(*pa66) == typeid(*pa77)" << endl;
}
else {
cout << "typeid(*pa66) != typeid(*pa77)" << endl;
}
if (typeid(*pa88) == typeid(*pa77)) {
cout << "typeid(*pa88) == typeid(*pa77)" << endl;
}
else {
cout << "typeid(*pa88) != typeid(*pa77)" << endl;
}
if (typeid(*pa88) == typeid(Child32)) {
cout << "typeid(*pa88) == typeid(Child32)" << endl;
}
else {
cout << "typeid(*pa88) != typeid(Child32)" << endl;
}
如上两个运算符要能得到正确的值--需要父类和子类之间有虚函数
虚函数表。
只要类有虚函数存在,编译器就会对该类产生一个虚函数表。
这个虚函数表中的第一项,指向的是这个类所关联的 type_info对象。
虚函数表的其他项,都对应一个虚函数。
当我们使用
Parent *pa = new Son;
的时候,pa对象有一个隐藏指针,指向son里面的虚函数表。
那么 就很好理解了,pa 这个隐藏指针---->指向son 的虚函数表,
该函数表 的第一项就指向 son
其他项都指向 虚函数。