运行时类型识别(Run-time type identification , RTTI)

31 篇文章 0 订阅
15 篇文章 0 订阅

参考:https://www.cnblogs.com/gaohongchen01/p/4085908.html

           http://www.cppblog.com/smagle/archive/2010/05/14/115286.html

 运行时类型识别(Run-time type identification , RTTI),是指在只有一个指向基类的指针或引用时,确定所指对象的准确类型的操作。其常被说成是C++的四大扩展之一(其他三个为异常、模板和名字空间)。

使用RTTI的两种方法:

  1、typeid()

  第一种就像sizeof(),它看上像一个函数,但实际上它是由编译器实现的。typeid()带有一个参数,它可以是一个对象引用或指针,返回全局typeinfo类的常量对象的一个引用。可以用运算符“= =”和“!=”来互相比较这些对象,也可以用name()来获得类型的名称。如果想知道一个指针所指对象的精确类型,我们必须逆向引用这个指针。比如:

复制代码

#include <typeinfo>
#include <iostream>
#include <cmath>
using namespace std;
class Shape
{
public :
    int area(float r)
    {
        float s=3.14*pow(r,2);
        return s;
    }
};
int main()
{  
    Shape* shape=new Shape;
    cout<< typeid(*shape).name()<<endl;
    system("pause");
}

复制代码

  运行结果为:

  为了保持一致性,typeid()也可以用于内部类型,所以下面的表达式结果为true:

typeid(36) == typeid(int)
typeid(0) == typeid(int)

int i;
typeid(i) == typeid(int)
typeid(&i) ==typeid(int*)

  可以用typeid 检查基本类型和非多态类型

复制代码

//可以用typeid 检查基本类型和非多态类型: 
#include <typeinfo>
#include <iostream>
using namespace std;
typedef  unsigned int UINT ;
int main()
{  
    cout<< typeid(UINT).name()<<endl;
    cout<< typeid(string).name()<<endl;
    system("pause");
}

复制代码

  运行结果如图所示:

  用typeid分析指针与引用的区别

复制代码

#include <typeinfo>
#include <iostream>
using namespace std;
class B
{   
public:  
    virtual double fun() 
    { 
        return 0.1; 
    }   
};
class D :public B   
{
};
int main()
{   
    B *p = new D;    
    B &r = *p;    //无名对象照样有别名
    cout<<(typeid(p)==typeid(B*)); //仅指向子类中父类部分
    cout<<(typeid(p)!=typeid(D*));  //而非指向整个子类对象
    cout<<(typeid(r)==typeid(D));   //引用的类型却是子类的
    cout<<(typeid(*p)==typeid(D)); //间址访问的是子类对象
    cout<<(typeid(*p)!=typeid(B));  //而非父类
    cout<<(typeid(&r)==typeid(B*)); //引用的地址是父类的
    cout<<(typeid(&r)!=typeid(D*));  //而非子类的
    system("pause");
    return 0;
}

复制代码

  运行结果:

  2、dynamic_cast <type-id> (expression)

  该运算符把expression转换成type-id类型的对象。Type-id 必须是类的指针、类的引用或者void*,不可是对象;如果 type-id 是类指针类型,那么expression也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用。

  dynamic_cast主要用于类层次间的上行转换下行转换,还可以用于类之间的交叉转换。在类层次间进行上行转换时,dynamic_caststatic_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

复制代码

#include <typeinfo>
#include <iostream>
using namespace std;
class Shape
{
public:
    virtual void Draw()
    {
    }
};
class Circle:public Shape
{
public:
    virtual void Draw()
    {
    }
};
int main()
{  
    Shape* sp=new Circle;
    Circle* cp=dynamic_cast<Circle*>(sp);
    if(cp)  
        cout<<"cast successful"<<endl;;
    system("pause");
}

复制代码

  运行结果:

如何使用RTTI:

  • 先激活RTTI;
  • 对象所属类型必须是多态类族
  • 若使用dynamic_cast<>转换一个引用,则要使用异常处理机制,因为它可能抛出 std::bad_cast异常;当使用dynamic_cast<>运算符转换一个指针时,定要检查结果是否为NULL
  • 若使用typeid (*p)来检索对象的类型信息,又恰碰 p == NULL时,将抛出std::bad_typeid异常;

 

例子:

#include <iostream>
using namespace std;

class Base {};
class Derived: public Base {};

int main()
{
    Base b, *pb;
    pb = NULL;
    Derived d;

    cout << typeid(int).name() << endl
         << typeid(unsigned).name() << endl
         << typeid(long).name() << endl
         << typeid(unsigned long).name() << endl
         << typeid(char).name() << endl
         << typeid(unsigned char).name() << endl
         << typeid(float).name() << endl
         << typeid(double).name() << endl
         << typeid(string).name() << endl
         << typeid(Base).name() << endl
         << typeid(b).name()<<endl
         << typeid(pb).name()<<endl
         << typeid(Derived).name() << endl
         << typeid(d).name()<<endl
         << typeid(type_info).name() << endl;
         
    return 0;
}


    我分别用MS的V8和GUN的GCC编译该段代码并运行,结果分别为下面的左右二图。
      
    对比代码以及上面的文字描述,不知道各位是否已经有所明了(这里需要注意的是Base类的对象b和对象指针pb,他们的输出)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值