• C++中static_cast和dynamic_cast强制类型转换


    1.static_cast关键字(编译时类型检查)

    用法:

    • static_cast < type-id > ( expression ),该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性

    它主要有如下几种用法:

    • (1)用于基本数据类型之间的转换,如把int转换为char,把int转换成enum,但这种转换的安全性需要开发者自己保证(这可以理解为保证数据的精度,即程序员能不能保证自己想要的程序安全),如在把int转换为char时,如果char没有足够的比特位来存放int的值(int>127或int<-127时),那么static_cast所做的只是简单的截断,及简单地把int的低8位复制到char的8位中,并直接抛弃高位。
    • (2)把空指针转换成目标类型的空指针
    • (3)把任何类型的表达式类型转换成void类型
    • (4)用于类层次结构中父类和子类之间指针和引用的转换。

    对于static_cast,上行转换时安全的,而下行转换时不安全的
    因为static_cast的转换时粗暴的,它仅根据类型转换语句中提供的信息(尖括号中的类型)来进行转换,这种转换方式对于上行转换,由于子类总是包含父类的所有数据成员和函数成员,因此从子类转换到父类的指针对象可以没有任何顾虑的访问其(指父类)的成员。
    而对于下行转换为什么不安全,是因为static_cast只是在编译时进行类型检查,没有运行时的类型检查,具体原理在dynamic_cast中说明。

    2.dynamic_cast关键字(运行时类型检查)

    用法:

    【格式】dynamic_cast<type_id>(expression) :
    
    该运算符把expression转换为type_id 类型, type_id 可以为类的指针、类的引用、void*,expression为对应的指针或引用.
    
    • 1
    • 2
    • 3
    • dynamic_cast是四个强制类型转换操作符中最特殊的一个,它支持运行时识别指针或引用。
    • 首先,dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,
      这种检查不是语法上的,而是真实情况的检查。
    • 若对指针进行dynamic_cast,失败返回nullptr,成功返回正常cast后的对象指针;
    • 若对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用

    dynamic_cast,主要用于类层次间的转换:

    • 上行转换(子类转父类),转换安全,成功返回类对象指针, 此时和static_cast 作用一样。

    • 下行转换(父类转子类), 父类中要有虚函数,否则编译器报错。转换分几种情况:
      a. 父类指针指向子类对象,转换安全, dynamic_cast返回类对象指针。
      b.父类指针指向父类对象,转换不安全,dynamic_cast 返回nullptr。
      此时若使用static_cast, 返回非空指针,更不安全。

    • eg:

    #include 
    
    using namespace std;
    
    class A{
    public:
        A(){}
        virtual void eat()
        {
            std::cout<<"A::eat()"<<std::endl;
        }
    
        void sing(){
            std::cout<<"A::sing()"<<std::endl;
        }
        ~A(){};
    };
    
    class B : public A{
    public:
        B() {};
        void eat()
        {
            std::cout<<"B::eat()"<<std::endl;
        }
        void sing()
        {
            std::cout<<"B::sing()"<<std::endl;
        }
        ~B(){}
        int data;
    };
    
    
    int main()
    {
        A* a= nullptr;
        B* b = nullptr;
    
        A aa;
        B bb;
        b = &bb;
        // 安全的向上转型
        a = dynamic_cast<A*>(b);
        a->sing();
        a->eat();
        std::cout<<"===="<<std::endl;
        // 向下转型,向下转型时,父类必须含有虚函数,否则编译报错
        //父类指针指向子类对象,这样的dynamic_cast向下转换才是安全的
        a = &bb;
        b = dynamic_cast<B*>(a);
        
        b->sing();//yes
        b->eat();//yes
        std::cout<<"===="<<std::endl;
        //父类指针指向父类对象,这样的dynamic_cast向下转换是不安全的
        a = &aa;
        b = dynamic_cast<B*>(a);
        if (b == nullptr)
        {
            std::cout<<"the call is not safe "<<std::endl;
        }
        b->sing();//yes
        b->eat();//Segmentation fault
        std::cout<<"===="<<std::endl;
        
        //static_cast不做类型检查,不返回nullptr,不安全
        b = static_cast<B*>(a);
        if (b == nullptr)
        {
            std::cout<<"second the call is not safe "<<std::endl;
        }
    
        b->sing();//yes
        b->eat();//居然调用的基类的eat,不对
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
  • 相关阅读:
    【最全日期获取合集】js获取昨天,今天,明天,上周,本周,下周,上月,本月,下月,去年,本年,明年,上季度,本季度,下季度,向前推日期等【全覆盖,拿来即用】
    解锁新技能《Redis ACL SETUSER命令》
    Docker初级篇
    创建老版本react-native项目,以0.59.10为例(0.60.0之前的版本)
    linux内核获取本机网卡的统计信息
    Spring 远程命令执行漏洞分析(CVE-2022-22965)
    通达信l1l2行情接口-十档行情有哪些优势?
    elasticsearch-head安装及详细配置
    进程控制2——进程等待
    SQL 练习
  • 原文地址:https://blog.csdn.net/u011436427/article/details/126114942