ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++——简单的RTTI

2022-01-28 18:34:21  阅读:185  来源: 互联网

标签:info typeid const dynamic C++ 简单 RTTI type 指针


即运行阶段类型识别(Runtime Type Identification)

 C++有三个支持RTTI的元素

1.dynamic_cast,使用一个基类的指针生成一个指向派生类的指针,失败返回0,即空指针。

尖括号表示括号中的类型能否安全的转为尖括号中的类型

本质上就是个更加规范的类型转换

2.typeid, 返回一个指出对象类型的值(可接受类名和结果为对象的表达式)

3.type_info结构体,存储了有关特定类型的信息。

dynamic_cast

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

class Grand
{
private:
    int hold;
public:
    explicit Grand(int h = 0) : hold(h) {}
    virtual void Speak() const
    {
        cout << "I am a Grand class\n";
    }
    virtual int Value() const
    {
        return hold;
    }
};

class Superb : public Grand
{
public:
    explicit Superb(int h) : Grand(h) {}
    void Speak() const override
    {
        cout << "I am a Superb class\n";
    }
    virtual void Say() const
    {
        cout << "I hold the superb value of " << Value() << endl;
    }
};

class Magnificent : public Superb
{
private:
    char ch;
public:
    explicit Magnificent(int h=0, char c = 'A') : Superb(h), ch(c) {}
    void Speak() const override
    {
        cout << "I am a Magnificent class\n";
    }
    void Say() const override
    {
        cout << "I hold the char" << ch << "and the int " << Value() << endl;
    }
};

Grand * GetOne();
int main()
{
    srand(time(NULL));
    //基类指针
    Grand * pg;
    //派生类指针
    Superb * ps;
    for(int i=0;i<5;i++){
        //基类指针随机指向一个对象
        pg = GetOne();
        pg->Speak();
        //RTTI判断能否安全转换
        //使用一个基类指针(pg)生成一个派生类指针(ps)
        if(ps = dynamic_cast<Superb*>(pg)){
            ps->Say();
        }else
            cout << "不安全的转换" << endl;
    }
    return 0;
}

Grand * GetOne()
{
    Grand * p;
    switch (rand() % 3) {
        case 0 : p = new Grand(rand()%100);
            break;
        case 1 : p = new Superb(rand()%100);
            break;
        case 2 : p = new Magnificent(rand()%100, 'A'+rand()%26);
            break;
    }
    return p;
}

运行结果 

 因为派生类指针不能指向基类,所以在这里

 不会调用Say()函数。这里的功劳就要归功于dynamic_cast<Superb*>(pg)他了

关于这里的语法可能有一些奇怪,赋值表达式的值是他的左值,如果转换成功,则ps的值为非零(true)。如果类型转换失败,则返回一个空指针(0,即false)。

特别的,当用引用作为参数时,应该用try,catch语句捕获错误。

也可用typeid函数,不用dynamic_cast,改为分别的以下判断并且使用强制转换。

//注意括号里的是对象,不是对象指针
typeid(Superb) == typeid(*pg);

但其实这样写不仅代码变长,也存在一些缺陷,比如需要靠大量的else if维护(或者switch)。

 typeid 运算符 和 type_info 结构体

前者能够确定两个对象是否为同种类型,并返回一个后者对象的引用(<typeinfo>中定义)。

type_info类重载了 == 和 != 。

如果有空指针比较(*pg(nullptr)),引发bad_typeid异常(异常类型从exception派生而来)。

其中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&);
};

对上面的程序进行小小的修改

        if(ps = dynamic_cast<Superb*>(pg)){
            ps->Say();
        }else
            cout << "不安全的转换" << endl;
        if(typeid(*pg)==typeid(Magnificent)){
            cout << "生成了一个Magnificent类,好耶!";
            //type_inf定义的类方法,返回const char *(即类名)
            cout << "use .name : " << typeid(*pg).name() << endl;
        }

输出结果

 

 

标签:info,typeid,const,dynamic,C++,简单,RTTI,type,指针
来源: https://blog.csdn.net/JAN6055/article/details/122734037

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有