C++显式类型转换

C++显式类型转换

码农世界 2024-05-16 后端 68 次浏览 0个评论

本文主要分析C++的4种显式类型转换

文章目录

  • static_cast
    • 基本数据类型转换
    • const
    • 用于类层次结构
    • void*
    • dynamic_cast
      • 继承中的转换
      • const_cast
      • reinterpret_cast
      • 参考资料

        我们使用显示类型转换,就是在告诉编译器要怎么解释这块内存。

        在早期C/C++中,显式的类型转换有如下两种形式

        type(expr); // 函数形式的显式类型转换
        (type)expr; // C语言风格 
        

        C++的新式显式类型转换

        cast-name(expression);
        
        • cast-name 有 static_cast、dynamic_cast、const_cast 和 reinterpret_cast 四种,表示转换的方式
        • type表示转换的目标类型
        • expression 是被转换的值

          下面详细讲解下这四种显式类型转换


          static_cast

          格式为 static_cast(expression)

          任何在编写程序时能够明确的类型转换都可以使用 static_cast:

          基本数据类型转换

          基本数据类型转换,比如将int转换为double,反之亦然,需要编写程序时确认安全性

          将 `int` 转换为 `double` 编译器可能的操作如下(VS2022 x64),比如有如下代码
          
          int x = 0;
          double y = static_cast(x);
          

          其汇编码为,cvtsi2sd 指令把源地址1个双字有符号整数变成1个双精度浮点数,xmm0 为英特尔处理器中的一个128位寄存器,movsd mmword ptr [y],xmm0 指令表示从 xmm0 寄存器中移动低64位到 y 地址

          C++显式类型转换

          const

          将非const对象转换为const对象 (但不能将const对象转换为非const对象,这个只有const_cast才能做到)

          如果转换底层 const 对象到非 const 对象,编译器会报表达式必须是可修改的左值错误

          C++显式类型转换

          顶层 const 也不可以被 static_cast 转换

          C++显式类型转换

          用于类层次结构

          父类和子类之间指针和引用的转换

          假设我们现在有两个类,父类 A 和其派生类 B

          class A {
          public:
          	virtual void foo() {
          		std::cout << "A::foo()" << std::endl;
          	}
          	int m_a = 0;
          };
          class B : public A
          {
          public:
          	virtual void foo() {
          		std::cout << "B::foo()" << std::endl;
          	}
          	int m_b = 0;
          };
          
          • 进行上行转换,即把子类对象的指针/引用转换为父类指针/引用,这种转换是安全的
            B b;
            static_cast(b).foo();
            B* bptr = new B;
            static_cast(bptr)->foo();
            

            输出如下

            C++显式类型转换

            • 进行下行转换,即把父类对象的指针/引用转换成子类指针/引用,这种转换是不安全的,因为没有运行时检查,所以需要在编写程序时确认安全性
              A* a = new A;
              std::cout << static_cast(a)->m_b << std::endl; // 不安全的,访问了申请外的内存
              

              输出如下

              C++显式类型转换

              void*

              把 void* 转换为目标类型的指针(这是极其不安全的),类似于上面父类指针转子类指针,可能会访问申请外的内存

              void* a = new A;
              std::cout << static_cast(a)->m_b << std::endl; // 不安全的,访问了申请外的内存
              

              输出如下

              C++显式类型转换


              dynamic_cast

              格式为 dynamic_cast(expression)

              相比static_cast,dynamic_cast 会在运行时检查类型转换是否合法,具有一定的安全性。由于运行时的检查,所以会额外消耗一些性能。需要注意的是 dynamic_cast 转换仅适用于指针或引用。

              继承中的转换

              1. 上行转换

              由子类指针/引用转换到父类指针/引用,与 static_cast 和隐式转换一样,都是安全的

              B* b = new B;
              A* a = dynamic_cast(b);
              std::cout << a->m_a << std::endl;
              

              可以看到下面的汇编代码中,只是把指针的值给到了 [a] 地址

              C++显式类型转换

              1. 下行转换

              由父类指针/引用转换到子类指针/引用,使用 dynamic_cast 进行下行转换有个条件,就是其操作数必须含有多态类类型,简单理解,父类得有虚函数。

              如果我们将之前 类A 和 类B 中的虚函数去掉,则会报错

              C++显式类型转换

              如果和之前一样,类 A 中有虚函数 foo(),那么执行 dynamic_cast 会发生什么

              A* a = new A;
              B* b = dynamic_cast(a);
              std::cout << b->m_b << std::endl;
              

              可以看到把类 B 和类 A 的运行时类型描述符放到了 r9 和 r8 寄存器中

              C++显式类型转换

              之后运行时动态类型转换,这里的实现原理简单描述为,我们在虚函数表 vtbl[-1] 的位置存放着指向类型信息的 tpye_info*,那么由于我们实际指向的对象的类是 A 其取出的 RTTI Type Descriptor 应该是类 A 我们和需要转换的类 B 的 RTTI Type Descriptor 比较,然后发现不匹配,此时转换失败,会返回一个 nullptr。

              C++显式类型转换

              如果 a 实际指向的是类 B 的对象,那么运行时转换成功。

              注意转换的是引用,转换失败会抛出 bad_cast 异常


              const_cast

              格式为 const_cast(expression)

              const_cast 用于移除类型的 const、volatile 和 _unaligned 属性

              const A* const a = new A;
              A* aa = const_cast(a);
              aa->m_a = 2;
              

              当然也可以用于添加 const

              C++显式类型转换


              reinterpret_cast

              格式为 reinterpret_cast(expression)

              非常激进的指针类型转换,在编译期完成,可以转换任何类型的指针,所以极不安全。非极端情况不要使用。


              参考资料

              C++笔记 · C++类型转换 —— 默默默默默

              C++对象模型之RTTI的实现原理 —— linux

转载请注明来自码农世界,本文标题:《C++显式类型转换》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,68人围观)参与讨论

还没有评论,来说两句吧...

Top