RTTI:Run-Time Type Identification。
那么RTTI如何来体现呢?这就要涉及到typeid和dynamic_cast这两个知识点了。为了更好的去理解,那么我们就通过一个例子来说明。这个例子大家已经非常熟悉了,如下:
首先定义一个Flyable类,在这个类当中有两个纯虚函数:takeoff(起飞)和land(降落)。我们又定义了一个鸟类,并且公有继承了Flyable类,既然public继承了Flyable,就要去实现起飞和降落这两个函数,此外,作为鸟类来说,还有一个自己特有的函数foraging(觅食)。同时,我们还定义了另外一个类Plane,其也以public方式继承了Flyable,并且也实现了起飞和降落这两个函数,此外,作为飞机类来说,其还有一个自己特有的函数Carry(运输)。
在使用的时候,我们假设有如下一个函数dosomething,它的传入参数是Flyable的一个指针,如下:
在这个函数当中,我们可以使用obj这个指针去调用起飞和降落这两个函数。同时,我们可以想一想,如果我们能够对传入的这个指针再做进一步的判断,如如说,我们判断出如果它是一个Bird对象指针,那么我们是不是就可以用这个指针去调用觅食这个函数呢?同理,如果我们判断出它是一个Plane对象指针,那么我们是不是也就可以用这个指针去调用运输这个函数呢?如果想要做到这样的效果,那么就要用到这节课开始提到的知识:运行时类型识别(RTTI)。
我们可以看到,当我们去实现dosomething这个函数的时候,如下:
我们在这调用了起飞函数,最后一行代码调用了降落函数。我们在调用完起飞这个函数之后,我们通过typeid(*obj).name()这样的方法就可以将当前的obj这个指针指向的实际的对象类型打印出来了(比如传入的是飞机,打印出来的就是Plane;如果传入的是Bird,那么打印出来的就是Bird)。当然,我们可以还可以通过if语句对类型进行比对,如果我们想要判断当前的obj是不是一个Bird类型,我们就可以通过上面的if判断语句的方法进行比对,比对完成之后,我们就可以将obj通过dynamic_cast的方式,将其转换为Bird指针。转换的时候,需要注意的是,dynamic_cast<Bird *>(obj),尖括号中是目标类型。转换完之后,我们就可以用bird这个指针去调用觅食这个函数。
总结:
dynamic_cast注意事项:
- l 只能应用于指针和引用的转换
- l 要转换的类型当中必须包含虚函数(如果没有虚函数,转换就会失败)
- l 转换成功返回子类的地址,失败返回NULL
typeid的注意事项:
- l type_id返回一个type_info对象的引用
- l 如果想要通过基类的指针获得派生类的数据类型,基类必须带有虚函数
- l 只能获取对象的实际类型(也就是说,即便这个类含有虚函数,也只能判断当前对象是基类还是子类,而没有办法判断当前指针是基类还是子类)
下面我们来看一看type_info中的内容,如下:
对于type_info这个类来说,当中我们用到一个name()函数。我们在之前的例子当中,通过typeid(*obj)获取到的就是一个type_info的引用,通过这个引用就可以调用name()这个成员函数(typeid(*obj).name()),那么这个被调用的name()成员函数就是在这所看到的name()。语句bool operator == (const type_info& rhs) const;是一个运算符重载(这部分内容后面介绍),大家只要知道,在进行了运算符重载之后,这里的==就可以使得前面的例子中两个type_info对象的比对了(typeid(*obj) = = typeid(Bird))。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include "flyable.h" #include "bird.h" #include "plane.h" using namespace std; void dosometing(Flyable *obj){ cout<< typeid(*obj).name()<<endl;//打印传入的对象指针是什么类型 obj->takeoff();//多态性,打印对象指针的takeoff方法 if(typeid(*obj) == typeid(Bird)){//判断对象是否为Bird Bird *bird = dynamic_cast<Bird*>(obj);//通过dynamic_cast将obj对象指针强转为Bird对象指针 bird->foraging();//执行Bird类特有成员函数 } else if(typeid(*obj) == typeid(Plane)){//同上 Plane *plane = dynamic_cast<Plane*>(obj); plane->carry(); } obj->land();//多态性,打印对象指针的land方法 } int main() { Bird b; dosometing(&b); Plane p; dosometing(&p); getchar(); return 0; }