• 【C++】运行时类型识别


    2 C++运行时类型识别

    Runtime Type Identification(RTTI) RTTI的意图:提供一个在运行时决定对象类型的标准机制。 有3个元素支持RTTI:dynamic_cast、typeid、type_info 注意事项:RTTI只可用于有虚函数的类

    22.1 dynamic_cast

    dynamic_cast是最常用的RTTI操作符。 回答的问题:是否能将某个对象的地址安全地赋值给一个特定类型的指针;同时也回答了强制类型转换是否安全的问题 格式:

    dynamic_cast(pt)

    pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type *,如果可以,则返回pg的地址;反之,返回0 也可以使用引用(应该不常用):

    dynamic_cast(rg)

    pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type &,如果可以,则返回pg的地址;反之,引发bad_cast异常(在typeinfo头文件中)

    22.2 typeid and type_info:

    22.2.1 typeid

    typeid决定两个对象的类型是否相等。 typeid的返回值为:type_info

    22.2.2 type_info

    type_info定义在typeinfo头文件中 type_info重载了== and != 操作符,因此可以比较两个类型是否相等

    22.2.3 typeid and type_info:

    格式:

    typeid(Magnificent) == typeid(*pg)//返回True(类型相等) or False(类型不等)

    bad_typeid异常:如果pg恰好是Null指针,则抛出bad_typeid异常,bad_typeid异常定义在typeinfo头文件中。 name()成员函数:type_info对象有成员函数name(),可以返回typeid(class)中class类的名称。 注意事项:如果发现使用typeid需要一长串if else,则要考虑使用dynamic_cast

    22.3 const_cast

    转换格式:

    const_cast < type-name > (expression)

    要求:type-name和expression必须是同一种类型,他们只在const和volatile上存在区别,转换成功就赋值就行,转换失败则返回0 与常规类型转换的不同:常规类型转换可以转换为不同类型,但是const_cast不允许不同类型的转换 基本原则:不允许将定义为const的变量转换为非const类型。

    22.4 static_cast

    格式:

    static_cast < type-name > (expression)

    当且仅当type-name类型可以隐式转换为expression类型,或反之,否则类型转换会报错,两者能互相转换 1.允许向上转换(继承类指针转换为基类指针) 2.允许向下转换(基类指针转换为继承类指针) 3.由于枚举类可以隐式转换为int,因此static_cast允许这类转换,并且允许将int类型转换为枚举类 4.允许将double转换为int,将int转换为double 5.允许将float转换为long,允许将long转换为float

    22.5 reinterpret_cast

    格式:

    reinterpret_cast < type-name > (expression)

    可以将指针类型转换为能够容纳该指针类型的整型,反之不能转换。 不能将函数指针转换为数据指针

    22.6 举例

    rtti.h

    #pragma once
    #include 
    using std::cout;
    #ifndef _RTTI1_H_
    #define _RTTI1_H_
    class Grand
    {
    private:
        int hold;
    public:
        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:
        Superb(int h = 0) : Grand(h) {}
        void Speak() const { cout << "I am a superb class!!\n"; }
        virtual void Say() const
        {
            cout << "I hold the superb value of " << Value() << "!\n";
        }
    };
    class Magnificent : public Superb
    {
    private:
        char ch;
    public:
        Magnificent(int h = 0, char c = 'A') : Superb(h), ch(c) {}
        void Speak() const { cout << "I am a magnificent class!!!\n"; }
        void Say() const {
            cout << "I hold the character " << ch <<
                " and the integer " << Value() << "!\n";
        }
    };
    #endif

    代码:main.cpp

    #include 
    #include 
    #include 
    #include"rtti1.h"
    #include 
    using std::cout;
    using std::endl;
    /*
    运行时类型识别:Runtime Type Identification(RTTI)
        RTTI的意图:提供一个在运行时决定对象类型的标准机制。
        有3个元素支持RTTI:dynamic_cast、typeid、type_info
        注意事项:RTTI只可用于有虚函数的类
    */
    Grand* GetOne();
    void change(const int* pt, int n);
    int main()
    {
        /*
        dynamic_cast:
            dynamic_cast是最常用的RTTI操作符。
            回答的问题:是否能将某个对象的地址安全地赋值给一个特定类型的指针;同时也回答了强制类型转换是否安全的问题
            格式:dynamic_cast(pt)
                pt能否安全的类型转换(*pt为Type或者*pt为Type的继承类)为Type *,如果可以,则返回pg的地址;反之,返回0
            也可以使用引用(应该不常用):dynamic_cast(rg)
                pt能否安全的类型转换(pt为Type或者pt为Type的继承类)为Type &,如果可以,则返回pg的地址;反之,引发bad_cast异常(在typeinfo头文件中)   
        */
        cout << "dynamic_cast***************************************************************" << endl;
        std::srand(std::time(0));
        Grand* pg;
        Superb* ps;
        for (int i = 0; i < 5; i++)
        {
            pg = GetOne();
            pg->Speak();
            if (ps = dynamic_cast(pg))  //如果可以转换,则if条件判断为1,则执行ps->Say();反之,不执行
                ps->Say();
        }
        /*
        typeid and type_info:
            typeid:
                typeid决定两个对象的类型是否相等。
                typeid的返回值为:type_info
            type_info:
                type_info定义在typeinfo头文件中
                type_info重载了== and != 操作符,因此可以比较两个类型是否相等
            typeid and type_info:
                格式:typeid(Magnificent) == typeid(*pg)//返回True(类型相等) or False(类型不等)
                bad_typeid异常:如果pg恰好是Null指针,则抛出bad_typeid异常,bad_typeid异常定义在typeinfo头文件中。
                name()成员函数:type_info对象有成员函数name(),可以返回typeid(class)中class类的名称。
            注意事项:如果发现使用typeid需要一长串if else,则要考虑使用dynamic_cast
        */
        cout << "typeid***************************************************************" << endl;
        for (int i = 0; i < 5; i++)
        {
            pg = GetOne();
            cout << "Now processing type " << typeid(*pg).name() << ".\n";
            pg->Speak();
            if (ps = dynamic_cast(pg))
                ps->Say();
            if (typeid(Magnificent) == typeid(*pg))
                cout << "Yes, you're really magnificent.\n";
        }
        /*
        const_cast:
            转换格式:const_cast < type-name > (expression)
            要求:type-name和expression必须是同一种类型,他们只在const和volatile上存在区别,转换成功就赋值就行,转换失败则返回0
            与常规类型转换的不同:常规类型转换可以转换为不同类型,但是const_cast不允许不同类型的转换
            基本原则:不允许将定义为const的变量转换为非const类型。
        */
        cout << "const_cast***************************************************************" << endl;
        int pop1 = 38383;
        const int pop2 = 2000;
        cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
        change(&pop1, -103);//转换了,因为pop1是非const类型
        change(&pop2, -103);//没转换,因为pop2是const类型
        cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
        /*
        static_cast:
            格式:static_cast < type-name > (expression)
            当且仅当type-name类型可以隐式转换为expression类型,或反之,否则类型转换会报错,两者能互相转换
            1.允许向上转换(继承类指针转换为基类指针)
            2.允许向下转换(基类指针转换为继承类指针)
            3.由于枚举类可以隐式转换为int,因此static_cast允许这类转换,并且允许将int类型转换为枚举类
            4.允许将double转换为int,将int转换为double
            5.允许将float转换为long,允许将long转换为float
        */
        cout << "static_cast***************************************************************" << endl;
        Grand x = Grand(10);//基类对象
        Grand * w = &x;//基类指针
        Superb z = Superb(11);//继承类对象
        Superb * pointer1 = &z;
        Superb * y = static_cast< Superb* >(w);//将基类指针转换为继承类指针 允许
        y->Speak();//只是允许但是不推荐,因为转换为继承类指针后可以调用继承类的成员方法,而基类没有该成员方法,会引发异常
        Grand * a = static_cast(pointer1);//将继承类指针转换为基类指针
        a->Speak();
        int varint1 = 99;
        double vardouble1 = 99.99;
        int var = static_cast(vardouble1);
        std::cout << "var = " << var << std::endl;
        double var1 = static_cast(varint1);
        std::cout << std::fixed <<"var1 = " << var1 << std::endl;
        /*
        reinterpret_cast:
            格式:reinterpret_cast < type-name > (expression)
            可以将指针类型转换为能够容纳该指针类型的整型,反之不能转换。
            不能将函数指针转换为数据指针
        */
        cout << "reinterpret_cast***********************************************************" << endl;
        struct dat { short a; short b; };
        long value = 0xA224B118;
        dat* pd = reinterpret_cast (&value);
        std::cout << std::hex << pd->a; // display first 2 bytes of value
    ​
        return 0;
    }
    Grand* GetOne() // generate one of three kinds of objects randomly
    {
        Grand* p = 0;
        switch (std::rand() % 3)
        {
        case 0: p = new Grand(std::rand() % 100);
            break;
        case 1: p = new Superb(std::rand() % 100);
            break;
        case 2: p = new Magnificent(std::rand() % 100,
            'A' + std::rand() % 26);
            break;
        }
        return p;
    }
    ​
    void change(const int* pt, int n)
    {
        int* pc;
        pc = const_cast(pt);
        *pc += n;
    }

    运行结果:

    dynamic_cast***************************************************************
    I am a grand class!
    I am a magnificent class!!!
    I hold the character Q and the integer 0!
    I am a magnificent class!!!
    I hold the character X and the integer 42!
    I am a magnificent class!!!
    I hold the character D and the integer 56!
    I am a superb class!!
    I hold the superb value of 29!
    typeid***************************************************************
    Now processing type class Magnificent.
    I am a magnificent class!!!
    I hold the character H and the integer 5!
    Yes, you're really magnificent.
    Now processing type class Grand.
    I am a grand class!
    Now processing type class Grand.
    I am a grand class!
    Now processing type class Grand.
    I am a grand class!
    Now processing type class Superb.
    I am a superb class!!
    I hold the superb value of 92!
    const_cast***************************************************************
    pop1, pop2: 38383, 2000
    pop1, pop2: 38280, 2000
    static_cast***************************************************************
    I am a grand class!
    I am a superb class!!
    var = 99
    var1 = 99.000000
    reinterpret_cast***********************************************************
    b118
    D:\Prj\_C++Self\_1已统计代码\_18Runtime_Type_Identification\Debug\_18Runtime_Type_Identification.exe (进程 3700)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
  • 相关阅读:
    vue3 + vite + ts + setup , 第十七练 vue3 中使用vue-router(一),router跳转传参/嵌套路由/路由重定向/别名
    微信小程序开发的OA会议之首页搭建
    (送源码)SSM&MYSQL民宿预订及个性化服务系统04846-计算机毕业设计
    无人机集群编队解决方案,适应多种飞行场景
    ESP32集成开发环境Espressif-IDE安装 – Windows
    代码随想录算法训练营day58||739. 每日温度 ||496.下一个更大元素 I ||503.下一个更大元素II
    Elasticsearch7.x.x开启X-pack鉴权,按步骤执行就能成功!
    情绪智力测试
    两台linux虚拟机之间实现免密登录
    2023最新SSM计算机毕业设计选题大全(附源码+LW)之java宾馆客户自助入住子系统lk8i3
  • 原文地址:https://blog.csdn.net/weixin_44410704/article/details/128022314