C++强制类型转换
总结一下.
C语言中的类型转换
在C语言中,类型转换主要有两种:隐式类型转换和显式类型转换。
- 隐式类型转换(Implicit Type Conversion) 在表达式中自动进行的类型转换,不需要使用特定的语法或运算法,比如常见的整数和浮点数之间的转换。
1 2
char c ='A'; int i =c; //隐式类型转换
- 显示类型转换(Explicit Type Conversion) 在表达式中使用特定的语法或运算符进行的类型转换,也称为强制类型转换。
1 2
float f =3.15; int i =(int)f;
C语言类型转换的不足
在C语言中。类型转换存在一些潜在的问题和不足之处,其中包括:
- 信息丢失:当一个较大的数据类型转换为一个较小的数据类型时,可能会发生信息丢失。例如,将一个浮点数转换为整数时,小数部分会被截断,导致精度丢失。
- 未定义行为:某些情况下,进行不适当的类型转换可能导致未定义的行为,这使得代码的行为不可预测。例如,在指针类型之间进行不正确的转换导致内存访问错误。
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; }
- 数据损坏:类型转换可能会导致数据损坏或失真。例如,将一个整数转换为一个较小的整数类型时,如果超出了目标类型的表示范围,结果可能会不正确。
- 可读性和可维护性:使用类型转换可能会降低代码的可读性和可维护性。在代码中使用大量的类型转换可能会使代码难以理解,并且增加了代码维护的复杂性。
- 难以排查错误:当类型转换被滥用或错误使用时,可能会导致代码中隐藏的错误。这些错误可能很难排查和修复,因为它们可能会在运行时产生不可预测的结果。
C++强制类型转换
在C++中,常见的类型转换方法包括隐式类型转换和显式类型转换,而显示类型转换又可以进一步细分为四种:static_cast、dynamic_cast、const_cast和reinterpret_cast。
- 静态转换(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; }
- 用于具多态的类实例指针或引用之间的转换
- 用于基本内置数据类型之间的转换
- 动态转换(dynamic_cast)
- 用于多态类型的安全转换,通常在基类和派生类之间转换时使用。
- 运行时执行类型检查,只能用于指针或引用类型,并且要求目标类型必须有虚函数。
- 如果转换不安全,返回空指针(在指针转换中),或抛出std::bad_cast异常(在引用转换中)。
1 2
Base* basePtr = new Derived(); Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 动态转换
- 常量转换(const_cast)
- 用于添加或删除’const’、’volatile’修饰符。
- 主要用于修改常量对象的常量性或者将常量引用转换为非常量引用,以允许对其进行修改。
1 2 3
const int x = 5; int& y = const_cast<int&>(x); // 取消常量性 y = 10; // 合法
- 重解释转换(reinterpret_cast)
- 用于不同类型之间的位模式重新解释。
- 是一种较低级别的转换,可以将任何指针类型转换为其他指针类型,也可以将任何整数类型转换为指针类型,反之亦然
- 非常危险,可能导致未定义的行为,应谨慎使用。
1
int* ptr = reinterpret_cast<int*>(somePointer);
本文由作者按照 CC BY 4.0 进行授权