RTTI

RTTI,即 Run-Time Type Identification

在C++ 中,也称为 运行时类型识别
这里写图片描述
RTTI 的体现方式:
这里写图片描述
看如下实例

定义一个Flyable 类,其中有两个纯虚函数:takeoff() 和 land()
这里写图片描述
再定义一个Bird 类,它 public 的继承了 Flyable 类,并实现了 takeoff() 和 land(),并拥有自己独有的函数:foraging(),即觅食
这里写图片描述
再定义一个Plane 类,它 public 的继承了 Flyable 类,并实现了 takeoff() 和 land(),并拥有自己独有的函数:carry(),即 运输
这里写图片描述
在使用时:
这里写图片描述
假设有这样一个函数:doSomething(),其参数是 Flyable 的一个指针,在函数体中可以使用obj 去调用 takeoff() 和 land()。

再设想一下,如果能够对传入的指针再做进一步的判断,即:

  • 如果判断它是一个Bird 的对象指针,就能使用指针去调用 觅食 的函数

  • 如果判断它是一个Plane 的对象指针,就能使用指针去调用 运输 的函数

如果想要做到上述判断,就要使用RTTI 运行时类型识别
这里写图片描述
typeid(*obj).name() 可以获得当前 obj 指针指向的实际的对象类型,用cout 可以将其打印出来,再通过 if 语句进行比对,比对完成后,就可以将obj 通过 dynamic_cast 的方式将其转化成为 bird 的指针 。

转化时要注意:dynamic_cast 后面跟两个尖括号,中间写上要转化的目标类型。

总结:

关于 dynamic_cast 的注意事项:

  • 只能应用与指针和引用的转换,即只能转化为某一个类型的指针或某一个类型的引用,而不能是某类型本身

  • 要转化的类型中必须包含虚函数,如果没有虚函数,转换就会失败

  • 如果转换成功,返回子类的地址,如果转换失败,返回NULL

关于 typeid 的注意事项:

  • typeid 返回一个 type_info 的对象引用

  • 如果想通过基类的指针指向派生类的数据类型,基类就必须要带有虚函数,否则,在使用typeid 时,就只能返回定义时所使用的数据类型

  • typeid 只能获取对象的实际类型,即便这个类含有虚函数,也只能判断当前对象是基类还是派生类,而不能判断当前指针是基类还是派生类

type_info 中的内容:

class type_info
{
private:
    type_info(const type_info&);
    type_info& operator=(const type_info&);//type_info类的复制构造函数和赋值运算符是私有的。
public:
    virtual ~type_info();//析构函数
    bool operator==(const type_info&)const;//在type_info类中重载了==运算符,该运算符可以比较两个对象的类型是否相等。
    bool operator!=(const type_info&)const;//重载的!=运算符,以比较两个对象的类型是否不相等
    const char* name()const;//使用得较多的成员函数name,该函数返回对象的类型的名字。前面使用的typeid(a).name()就调用了该成员函数
    bool before(const type_info&);
};

在上例中,typeid(*obj) 获取到的就是一个 type_info 的引用,通过该引用就能调用 type_info 中的 name() 函数。

type_info 中的 bool operator==(const type_info& rhs) const; 即运算符重载,通过它就可以进行两个type_info 对象的比对。

程序:

//Flyable.h

#ifndef FLYABLE_H
#define FLYABLE_H

#include <iostream>
using namespace std;


//接口类
class Flyable
{
public:
    virtual void takeoff() = 0;
    virtual void land() = 0;
};

#endif
//Bird.h

#ifndef BIRD_H
#define BIRD_H

#include"Flyable.h"

class Bird:public Flyable
{
public:
    void foraging();
    virtual void takeoff();
    virtual void land();
};

#endif
//Bird.cpp

#include"Bird.h"

void Bird::foraging()
{
    cout << "Bird--foraging" << endl;
}

void Bird::takeoff()
{
    cout << "Bird--takeoff" << endl;
}

void Bird::land()
{
    cout << "Bird--land" << endl;
}
//Plane.h

#ifndef PLANE_H
#define PLANE_H

#include"Flyable.h"

class Plane:public Flyable
{
public:
    void carry();
    virtual void takeoff();
    virtual void land();
};

#endif
//Plane.cpp

#include"Plane.h"

void Plane::carry()
{
    cout << "Plane--carry" << endl;
}

void Plane::takeoff()
{
    cout << "Plane--takeoff" << endl;
}

void Plane::land()
{
    cout << "Plane--land" << endl;
}
//main.cpp

#include"Bird.h"
#include"Plane.h"

void doSomething(Flyable *obj);

int main(void)
{
    Bird b;
    Plane p;
    doSomething(&b);
    cout << endl;
    doSomething(&p);

    //对typeid的验证
    /*cout << endl;
    int i = 0;
    cout << typeid(i).name() << endl;
    Flyable *t = new Bird();
    cout << typeid(t).name() << endl;
    cout << typeid(*t).name() << endl;*/

    system("pause");
    return 0;
}

void doSomething(Flyable *obj)
{
    //这里打印的是数据类型, 传入的不是obj指针而是对象*obj
    cout << typeid(*obj).name() << endl;

    obj->takeoff();

    //两个type_info对象的比对运算符重载
    if (typeid(*obj) == typeid(Bird))
    {
        //转化为Bird的指针
        Bird *bird = dynamic_cast<Bird *>(obj);
        bird->foraging();
    }
    if (typeid(*obj)==typeid(Plane))
    {
        Plane *plane = dynamic_cast<Plane *>(obj);
        plane->carry();
    }
    obj->land();
}

运行一览:
这里写图片描述

此文章转载自:https://blog.csdn.net/siwuxie095/article/details/71190391

猜你喜欢

转载自blog.csdn.net/chen134225/article/details/81319602
今日推荐