• 猿创征文|[C++ 从入门到精通] 6.static_cast、dynamic_cast等显示类型转换


    • 📢博客主页:https://loewen.blog.csdn.net
    • 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
    • 📢本文由 丶布布原创,首发于 CSDN,转载注明出处🙉
    • 📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨


    一. 隐式类型转换

    含义:隐式类型转换:系统自动进行,不需要开发人员介入。

    int m = 3 + 45.6;      //48     
    
    • 1

    因为返回的int型,所以系统自动去除掉小数点后面的值,结果为48,这种属于隐式转换类型。


    二. 显式类型转换(强制类型转换)

    1、C语言的强制类型转换风格:

    //int k = 5 % 3.2;     //语法错误:%非法,右操作数包含“double”类型
    int k = 5 % int(3.2);  //将3.2强制转换成int型3,C语言风格的强制类型转换,结果:余2   
    
    • 1
    • 2

    上面这种C语言的强制类型转换风格,没有类型检查,往整型上硬转,转的对不对需要程序员提供保障,例如强制将字符串类型转换成int类型:(int)"asa"就不行了。

    2、针对上面的情况,C++提供了4种更为安全的强制类型转换:

    • static_cast显式转换类型;
    • dynamic_cast显式转换类型;
    • const_cast显式转换类型;
    • reinterpret_cast显式转换类型;

    C++强制类型转换通用书写形式:强制类型转换名 <type> ( express );

    • 强制类型转换名static_castdynamic_castconst_castreinterpret_cast4种类型
    • type:转换到的目标类型
    • express:待转换的类型(值或变量),即express转换成type类型

    每一种强制类型转换都有其特定的目的,这样可以提供更丰富的含义和功能、更好的类型检查机制,方便代码的编写和维护。


    static_cast显示转换

    含义: static_cast静态转换,理解成“正常转换”(编译时进行类型检查)。

    适用场合:

    1、相关类型转换,比如整型int和实型qeal之间的转换。

    double f = 100.34;
    
    int ic1 = f;                     //方式一:隐式转换直接转
    int ic1 = int(f);                //方式二:C风格的强制类型转换
    int ic2 = static_cast<int>(f);   //方式三:C++风格的强制类型转换
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、继承关系中子类转换成父类类型(向上转换:隐式转换),可以直接转换,也可以使用static_cast转。

    class A {};
    class B : public A {};
    
    A a;
    B b;
    a = b;                  //方式一:隐式转换直接转
    a = static_cast<A>(b);  //方式二:static_cast转换
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、void *与其他类型指针之间的转换。void *:无类型指针(万能指针):可以指向任何指针类型

    int i = 10;
    int *p = &i;
    void *q = p;                       //方式一:隐式转换,系统内部自己转
    void *q = static_cast<void *>(p);  //方式二:static_cast转换
    
    • 1
    • 2
    • 3
    • 4

    不适用场合:

    1、指针类型之间的转换,比如int *double *double *float *等。

    double d = 100.34;
    double *pd = &d;
    int *pi = static_cast<int *>(pd);   //达咩,类型转换无效
    
    • 1
    • 2
    • 3

    小结:static_cast含义跟C语言中的强制类型转换差不多:

    • C风格的强制类型转换编译器自己能够进行的隐式类型转换都可以用static_cast显示完成转换(一般隐式转换让系统内部自己转就好了,不需要static_cast转换)。
    • C风格的强制类型转换一样,使用static_cast也要保证转换的安全性和正确性,比如int i = (int)“asa”这种情形不应该出现。

    dynamic_cast显示转换

    含义: dynamic_cast:能够将基类指针引用安全的转换为派生类的指针引用(运行时进行类型检查)。

    ps:只要dynamic_cast运算符能转换成功,就说明这个指针实际上是要转换到的那个类型,否则不能转换成功。这也间接的帮助我们完成了运行时的类型识别和安全检查(弥补C语言风格的强制转换式的不足)。

    适用场合:

    1、有继承关系父类指针转换成子类指针(向下显示转换)

    struct Father{ /*父类Father*/ };
    struct Son: Father{ /*基类Father的子类B*/ };
            
    Father *father = new Son;
    Son *son = (Son *)(father);  //C风格的强制类型转换:硬把父类指针Father *转换成子类指针Son *,可以
    //son->子类成员               //可以,能够正常调用Son类的成员函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这种转换需要我们明确父类指针father是指向子类Son对象的(Father *father = new Son)才是安全的。否则明明father是指向Son对象的,却被强制转换成其他类的指针,再调用就不安全了。此外,如果在他人的代码中看到一个指针father,想要确认这个指针到底是指向本身类Father对象的、子类Son对象还是其他类的对象就太好区分,所以应该使用dynamic_cast来完成父类指针到子类指针的强制转换:

    struct Father{ /*父类Father*/ };
    struct Son: Father{ /*基类Father的子类B*/ };
            
    Father *father = new Son; 
    Son *son =  dynamic_cast<Son *>(father);
    if (son != nullptr)     //对于引用,如果用dynamic_cast转换失败,系统会抛出std::bad_cast异常
    {
        cout << "father实际是一个Son类型" << endl;  //在这里操作Son里面的成员函数、成员变量都能够操作并且安全的操作
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意:使用dynamic_cast显示转换父类指针时要保证父类中一定要有虚函数virtual,否则会报错:运行dynamic_cast操作符必须包含多态类类型。

    2、有继承关系父类引用转换成子类引用(用的较少,了解)

    struct Father{ /*父类Father*/ };
    struct Son: Father{ /*基类Father的子类B*/ };
     	      
    Father *father1 = new Son;
    Father &father2 = *father1;
    try
    {
        Son &son = dynamic_cast<Son &>(father2);    //转换成功
    }
    catch (std::bad_cast)
    {
        cout << "father2实际不是一个Son类型" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    const_cast显示转换

    含义:const_cast去除指针或引用的const属性。该转换能够将const性质转换掉或去除掉(编译时进行类型检查)。

    错误示范:

    const int ai = 90;
    int ai2 = const_cast<int>(ai);
    
    • 1
    • 2

    结果:

    在这里插入图片描述
    正确示范:

    const int ai = 90;
    const int *ai2 = &ai;
    int *ai3 = const_cast<int *>(ai2);   //截止到这里都没问题
    *ai3 = 120;  //注意:这种写值行为是一种未定义行为(实际结果不可控,因为*ai3转换之前是常量const int ai,所以不要往里写值,正常调用指针对象没问题)
    
    • 1
    • 2
    • 3
    • 4

    reinterpret_cast显示转换

    reinterpret_cast 处理无关类型之间的转换,也就是两个转换类型之间没有什么关系,就等于可以乱转、自由转,非常随意(编译时进行类型检查)

    ps: reinterpret:重新解释,将操作数内容解释为另一种不同的类型(能把操作数的类型都转了)。

    适用场合:

    1、将一个整型(地址)转换成指针,一种类型指针转换成另一种类型指针,按照转换后的类型重新解释内存中的内容。

    2、将一个指针类型转换成一个整型。

    int i = 10;
    int *p= &i;
    
    int *pi = reinterpret_cast<int *>(&i);    //这个没啥说的
    char *pc = reinterpret_cast<char *>(p);   //int *也可以转换成char *,语法对,但是没什么屌用
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ps:reinterpret_cast被认为是危险的类型转换,虽然其可以随便转换,而且编译器也不报错,但是需要合乎规则的用,不然就没什么意义了。这里了解一下,防止看别人代码不知道什么意思。


    三. 总结

    1. 所有强制类型转换,不建议使用,强制类型转换能够抑制编译器报错。
    2. 学习目的:认识这些类型转换符,方便大家阅读别人代码。
    3. 资料说:reinterpret_cast危险,我们需要合乎规则的用,不要乱用;使用const_cast意味着设计缺陷。
    4. 如果实在需要使用强制类型转换,不要再使用C语言风格的类型转换了,而是用上面C++风格的类型转换,一般static_castreinterpret_cast能够很好的取代C语言风格的强制类型转换。

    下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。
  • 相关阅读:
    【Note】CNN与现代卷积神经网络part4(附PyTorch代码)
    设计模式在参数校验中的使用
    C/C++内存管理
    C++实现线程安全的map
    3.6 空值的处理
    python3-GUI概述及应用
    【HDLBits 刷题 10】Circuits(6)Finite State Manchines 10-17
    Java JavaMail通过SMPT发送邮件
    thinkphp6 入门(4)--数据库操作 增删改查
    原来单元测试可以这么简单
  • 原文地址:https://blog.csdn.net/weixin_43197380/article/details/126675771