文章

C++强制类型转换

总结一下.

C语言中的类型转换

在C语言中,类型转换主要有两种:隐式类型转换和显式类型转换。

  1. 隐式类型转换(Implicit Type Conversion) 在表达式中自动进行的类型转换,不需要使用特定的语法或运算法,比如常见的整数和浮点数之间的转换。
    1
    2
    
    char c ='A';
    int i =c; //隐式类型转换
    
  2. 显示类型转换(Explicit Type Conversion) 在表达式中使用特定的语法或运算符进行的类型转换,也称为强制类型转换。
    1
    2
    
     float f =3.15;
     int i =(int)f;
    

C语言类型转换的不足

在C语言中。类型转换存在一些潜在的问题和不足之处,其中包括:

  1. 信息丢失:当一个较大的数据类型转换为一个较小的数据类型时,可能会发生信息丢失。例如,将一个浮点数转换为整数时,小数部分会被截断,导致精度丢失。
  2. 未定义行为:某些情况下,进行不适当的类型转换可能导致未定义的行为,这使得代码的行为不可预测。例如,在指针类型之间进行不正确的转换导致内存访问错误。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
     #include <stdio.h>
     int main() {
     int arr[3] = {1, 2, 3};
     int *ptr = arr;  // ptr指向数组arr的第一个元素
     printf("%d\n", ptr[0]); 
    
     // 错误的指针类型转换
     float *floatPtr = (float *)ptr;  // 将int指针转换为float指针
    
     // 尝试使用错误类型的指针访问数组元素
     printf("%f\n", floatPtr[0]);  // 未定义行为,可能导致内存访问错误
    
     return 0;
     }
    
  3. 数据损坏:类型转换可能会导致数据损坏或失真。例如,将一个整数转换为一个较小的整数类型时,如果超出了目标类型的表示范围,结果可能会不正确。
  4. 可读性和可维护性:使用类型转换可能会降低代码的可读性和可维护性。在代码中使用大量的类型转换可能会使代码难以理解,并且增加了代码维护的复杂性。
  5. 难以排查错误:当类型转换被滥用或错误使用时,可能会导致代码中隐藏的错误。这些错误可能很难排查和修复,因为它们可能会在运行时产生不可预测的结果。

C++强制类型转换

在C++中,常见的类型转换方法包括隐式类型转换和显式类型转换,而显示类型转换又可以进一步细分为四种:static_cast、dynamic_cast、const_cast和reinterpret_cast。

  1. 静态转换(static_cast)
    • 用于基本内置数据类型之间的转换
      1
      
       float data = static_cast<float>(1)
      
    • 用于指针之间的类型转换
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
     #include <iostream>
     using namespace std;
    
     int main()
     {
     int type_int =10;
     //float* float_ptr1= &type_int; //隐式转换无效 error: cannot convert ‘int*’ to ‘float*’ in initialization
     //float* float_ptr2= static_cast<float*>(&type_int); //error: invalid static_cast from type ‘int*’ to type ‘float*’
     float* float_ptr3= (float*)&type_int;
     cout <<"float_ptr3:"<<*float_ptr3<<endl; //编译器运行通过,但是输出不对float_ptr3:1.4013e-44
    	
     void* void_ptr=&type_int; //任何指针都可以隐士转换为void*
     //float* float_ptr4 = void_ptr; //error: invalid conversion from ‘void*’ to ‘float*
     float* float_ptr5 = static_cast<float*>(void_ptr);	
     cout <<"float_ptr5:"<<*float_ptr5<<endl; //编译器运行通过,但是输出不对float_ptr5:1.4013e-44
     float * float_ptr6 = (float *) void_ptr;
      cout <<"float_ptr6:"<<*float_ptr6<<endl; //编译器运行通过,但是输出不对float_ptr6:1.4013e-44
     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
      
       #include <iostream>
       using namespace std;
      
       class A
       {
           public:
            int a{1};
       };
       class B
       {
           public:
               int b{2};
       };
       class C: public A, public B
       {
           public:
               int c{3};
       };
      
       int main()
       {
           C c;
           A* a_ptr =static_cast<A*>(&c);//上行指针转换正常
           cout<<"A a: "<< a_ptr->a<<endl;
           B* b_ptr =static_cast<B*>(&c);//上行指针转换正常
           cout<<"B b: "<< b_ptr->b<<endl;
           A& a_ref =static_cast<A&>(c);//上行引用转换正常
           cout<<"A a: "<< a_ref.a<<endl;
           B& b_ref =static_cast<B&>(c); //上行引用转换正常
           cout<<"B b: "<< b_ref.b<<endl;
      	
           A a;
           B b;
           C* c_ptr1 =static_cast<C*>(&a);
           C* c_ptr2 =static_cast<C*>(&b);	
           cout<<"c_ptr1 c: "<<c_ptr1->c<<endl;  //2 下行转换指针无效,编译通过,结果不对
           cout<<"c_ptr2 c: "<<c_ptr2->c<<endl;  //1 下行转换指针无效,编译通过,结果不对
           C& c_ref1 =static_cast<C&>(a);
           C& c_ref2 =static_cast<C&>(b);
           cout<<"c_ref1 c: "<<c_ref1.c<<endl;  //2 下行转换引用无效,编译通过,结果不对
           cout<<"c_ref2 c: "<<c_ref2.c<<endl;  //1 下行转换引用无效,编译通过,结果不对
       return 0;
       }
      
    • 用于具多态的类实例指针或引用之间的转换
  2. 动态转换(dynamic_cast)
    • 用于多态类型的安全转换,通常在基类和派生类之间转换时使用。
    • 运行时执行类型检查,只能用于指针或引用类型,并且要求目标类型必须有虚函数。
    • 如果转换不安全,返回空指针(在指针转换中),或抛出std::bad_cast异常(在引用转换中)。
      1
      2
      
       Base* basePtr = new Derived();
       Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 动态转换
      
  3. 常量转换(const_cast)
    • 用于添加或删除’const’、’volatile’修饰符。
    • 主要用于修改常量对象的常量性或者将常量引用转换为非常量引用,以允许对其进行修改。
      1
      2
      3
      
       const int x = 5;
       int& y = const_cast<int&>(x); // 取消常量性
       y = 10; // 合法
      
  4. 重解释转换(reinterpret_cast)
    • 用于不同类型之间的位模式重新解释。
    • 是一种较低级别的转换,可以将任何指针类型转换为其他指针类型,也可以将任何整数类型转换为指针类型,反之亦然
    • 非常危险,可能导致未定义的行为,应谨慎使用。
      1
      
        int* ptr = reinterpret_cast<int*>(somePointer);
      
本文由作者按照 CC BY 4.0 进行授权