RTTI & dynamic_cast

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;
}



猜你喜欢

转载自blog.csdn.net/yuanchunsi/article/details/78938145
今日推荐