C++之运行时类型信息(RTTI)

运行时类型信息RTTI(run time type identification)就两个:typeid和dynamic_cast。其类型信息来自于运行时,所以这两个主要应用于实现多态的父子类之间。

一、typeid

typeid是一种运算符,可以获得变量包括对象的类型,作为一个获取运行时类型信息的运算符,目的并不是获取普通变量的类型,而是对象指针的类型。

#include<iostream>
#include<typeinfo>

using namespace std;

class A {
public:
    virtual ~A() {}
};

class B :public A {
public:
    B() {}
};

int main() {
    B b;
    A *pa = &b;
    cout << typeid(pa).name() << endl;
    cout << typeid(*pa).name() << endl;
    system("pause");
    return 0;
}

输出结果:

这里写图片描述
typeid(pa)会生成一个对象,然后调用name函数,可以看到typeid(pa).name()获得的仍然还是A的类型,只有typeid(*pa).name()才可以或者其真正的类型是B。

typeid重载了操作符== !=进行比较,函数name()则返回类型名称,typeid的赋值操作符重载和拷贝构造均是私有的,因此外部不能对其进行赋值或者拷贝的操作。

typeid主要根据返回类型,用作调试。

if(typeid(*pa).name()  != typeid(b).name())
    cout << typeid(pa).name() << endl;
if(typeid(*pa).name()  == typeid(b).name())
    cout << typeid(*pa).name() << endl;

像这样先判断pa实际指向的是什么类型的对象,然后再进行操作。

二、dynamic_cast

具有继承关系的父子类之间,子类是可以隐式转换成父类的,但父类不能隐私转换成子类,那么必然可以显示转换了,这里就用到了dynamic_cast。
首先说明一点,dynamic_cast只能用于具有虚函数的父类转换成子类,否则就会报错。

class A {
public:
    virtual ~A() {}
};

class B :public A {
public:
    B() {}
};

class C : public A {

};

class D {};

int main() {
    B b;
    A *pa = &b;
    B *pb = dynamic_cast<B*>(pa);
    cout << pb << endl;
    C *pc = dynamic_cast<C*>(pa);
    cout << pc << endl;
    D *pd = dynamic_cast<D*>(pa);
    cout << pd << endl;
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

dynamic_cast先检查指针所指的类型是否含有虚函数,含有,则编译通过,否则编译就会出错。再者判断该指针所指向的类型与要转换的类型是否具有一种“is a”的关系,也就是说父子类的关系,如果是“is a”的关系,dynamic_cast就会返回对象的地址,否则,dynamic_cast会返回NULL。
这也是为什么上面例子中后两个地址都是0的关系。对于:

C *pc = dynamic_cast<C*>(pa);

虽然C继承自A,但pa这个指针实际指向的是B类对象,也就是说将B类对象转换成C类,现在不是“is a”的关系,故dynamic_cast会返回一个NULL。

从dynamic_cast的返回值可以看出dynamic_cast是很安全的,可以转换的转,不可以的成功,但会返回NULL。

int main() {
    B b;
    B *pbb;
    A *pa = &b;
    B *pb = dynamic_cast<B*>(pa);    //成功  安全
    cout << pb << endl;
    C *pc = dynamic_cast<C*>(pa);    //成功  安全
    cout << pc << endl;
    D *pd = dynamic_cast<D*>(pa);   //成功  安全
    cout << pd << endl;
    cout << "--------------------------" << endl;
    pb = static_cast<B*>(pa);      //成功  不安全
    cout << pb << endl;
    pc = static_cast<C*>(pa);       //成功  不安全
    cout << pc << endl;
    /*pd = static_cast<D*>(pa);    //编译不通过
    cout << pd << endl;*/
    cout << "--------------------------" << endl;
    pb = reinterpret_cast<B*>(pa);    //成功  不安全
    cout << pb << endl;
    pc = reinterpret_cast<C*>(pa);    //成功  不安全
    cout << pc << endl;
    pd = reinterpret_cast<D*>(pa);    //成功  不安全
    cout << pd << endl;
    cout << "--------------------------" << endl;
    system("pause");
    return 0;
}

这里让dynamic_cast与static_cast和reinterpret_cast这两种类型转换进行比较。

输出结果:

这里写图片描述

显然dynamic_cast要安全多了。reinterpret_cast是相当不安全的:

class A {
public:
    virtual ~A() {}
};

class B : public A {
public:
    B() {}
};

class C : public A {
public:
    C() {}
    void fun() {
        cout << "class C" << endl;
    }
};

class D {
public:
    void fun() {
        cout << "class D" << endl;
    }
};

int main() {
    B b;
    A *pa = &b;
    C *pc = reinterpret_cast<C*>(pa);
    cout << pc << endl;
    pc->fun();
    D *pd = reinterpret_cast<D*>(pa);
    cout << pd << endl;
    pd->fun();
    system("pause");
    return 0;
}

我在C类和D类中放入了自己独有的成员,同样强制转换,输出结果:

这里写图片描述

可以看到pa实际指向的B类对象分别顺利的转成了毫无关系的C和D,并且非常顺利的调用了专属于这两个类的方法,这是相当可怕的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值