--------------siwuxie095
这里介绍一个高大上的名词:RTTI
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()
再设想一下,如果能够对传入的指针再做进一步的判断,即:
(1)如果判断它是一个 Bird 的对象指针,就能使用指针去调用 觅食 的函数
(2)如果判断它是一个 Plane 的对象指针,就能使用指针去调用 运输 的函数
如果想要做到上述判断,就要使用 RTTI 运行时类型识别
typeid(*obj).name() 可以获得当前 obj 指针指向的实际的对象类型
用 cout 可以将其打印出来,再通过 if 语句进行比对,比对完成后,
就可以将 obj 通过 dynamic_cast 的方式将其转化成为 bird 的指针
转化时要注意:dynamic_cast 后面跟两个尖括号,中间写上要转化
的目标类型
总结:
关于 dynamic_cast 的注意事项:
(1)只能应用与指针和引用的转换,即 只能转化为 某一个类型的
指针 或 某一个类型的引用,而不能是 某类型本身
(2)要转化的类型中必须包含虚函数,如果没有虚函数,转换就会失败
(3)如果转换成功,返回子类的地址,如果转换失败,返回 NULL
关于 typeid 的注意事项:
(1)typeid 返回一个 type_info 的对象引用
(2)如果想通过基类的指针指向派生类的数据类型,基类
就必须要带有虚函数,否则,在使用 typeid 时,就只能返
回定义时所使用的数据类型
(3)typeid 只能获取对象的实际类型,即便这个类含有虚
函数,也只能判断当前对象是基类还是派生类,而不能判断
当前指针是基类还是派生类
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 <stdlib.h> #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) { //通过typeid获取到type_info的一个引用 //通过引用调用name()成员函数 返回数据类型 // //这里打印的是数据类型 传入的不是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(); }
//RTTI: Run-Time Type Identification 运行时类型识别 //RTTI 的体现方式:typeid 和 dynamic_cast // //dynamic_cast后面跟2个尖括号 <> 即dynamic<> 里面填上要转化的目标类型 // //dynamic_cast注意事项: //(1)只能应用于指针和引用的转换 //(2)要转换的类型必须包含虚函数 //(3)转换成功返回子类的地址,失败返回NULL // //typeid注意事项: //(1)typeid返回一个type_info对象的引用 //(2)如果想要通过基类的指针获得派生类的数据类型,基类必须带有虚函数 //(3)只能获取对象的实际类型 //(判断当前对象属于基类还是派生类 只能判断对象不能判断指针) // //关于type_info,如下: //class type_info //{ //public: // //name()函数 // const char* name() const; // //运算符重载 // bool operator==(const type_info& rhs) const; // bool operator!=(const type_info& rhs) const; // int before(const type_info& rhs) const; // virtual ~type_info(); //private: // .... //}; |
运行一览:
【made by siwuxie095】