C风格的强转:
隐式转换(编译器自动转换)
会出现警告,精度丢失
代码:
usingnamespacestd; intmain(intargc, char*argv[]) { charcc='X'; floatff=cc; // 隐式转换,不会告警。doubledd=3.38; longll=dd; // 隐式转换,会告警。。}
输出:
强制类型转换
不会出现警告,精度丢失一样存在
代码:
usingnamespacestd; intmain(intargc, char*argv[]) { charcc='X'; floatffc=static_cast<float>(cc); // 显式地使用static_cast进行强制类型转换,不会告警。doubledd=3.38; longllc=static_cast<long>(dd); // 显式地使用static_cast进行强制类型转换,不会告警。inta=int(dd); }
输出:
C++风格的强转:
C++强制类型转换
C风格的强制类型转换很容易理解,不管什么类型都可以直接进行转换,使用格式如下:
目标类型 b = (目标类型) a;
C++也是支持C风格的强制类型转换,但是C风格的强制类型转换可能会带来一些隐患,出现一些难以察觉的问题,所以C++又推出了四种新的强制类型转换来替代C风格的强制类型转换,降低使用风险。
在C++中,新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast,用于支持C++风格的强制类型转换。
C++风格的强制类型转换能更清晰的表明它们要干什么,程序员只要看一眼这样的代码,立即能知道强制转换的目的,并且,在多态场景也只能使用C++风格的强制类型转换。
一、static_cast
static_cast是最常用的C++风格的强制类型转换,主要是为了执行那些较为合理的强制类型转换,使用格式如下:
static_cast<目标类型>(表达式);
用于基本内置数据类型之间的转换
C风格:编译器可能会提示警告信息。
static_cast:不会提示警告信息。
usingnamespacestd; intmain(intargc, char*argv[]) { charcc='X'; floatff=cc; // 隐式转换,不会告警。floatffc=static_cast<float>(cc); // 显式地使用static_cast进行强制类型转换,不会告警。doubledd=3.38; longll=dd; // 隐式转换,会告警。longllc=static_cast<long>(dd); // 显式地使用static_cast进行强制类型转换,不会告警。}
用于指针之间的转换
C风格:可用于各种类型指针之间的转换。
static_cast:各种类型指针之间的不允许转换,必须借助void*类型作为中间介质。
usingnamespacestd; intmain(intargc, char*argv[]) { inttype_int=10; float*float_ptr1= (float*)&type_int; //C风格直接强转cout<<"C风格"<<"*float_ptr1 = "<<*float_ptr1<<endl; // float* char_ptr2 = static_cast<float*>(&type_int); // int* -> char* 使用static_cast转换无效void*void_ptr=&type_int; // 任何指针都可以隐式转换为void*float*float_ptr4=static_cast<float*>(void_ptr); // void* -> float* 使用static_cast转换成功cout<<"C++风格"<<"*float_ptr4 = "<<*float_ptr4<<endl; }
转换之后的数据是不精确的
不能转换掉expression的const或volitale属性
intmain(intargc, char*argv[]) { inttemp=10; constint*a_const_ptr=&temp; int*b_const_ptr=static_cast<int*>(a_const_ptr); // const int* -> int* 无效constinta_const_ref=10; int&b_const_ref=static_cast<int&>(a_const_ref); // const int& -> int& 无效volatileint*a_vol_ptr=&temp; int*b_vol_ptr=static_cast<int*>(a_vol_ptr); // volatile int* -> int* 无效volatileinta_vol_ref=10; int&b_vol_ref=static_cast<int&>(a_vol_ref); // volatile int& -> int& 无效}
四种强转详解:
C++的类型转换只是语法上的解释,本质上与C风格的类型转换没什么不同,C语言做不到事情的C++也做不到。
语法:
static_cast<目标类型>(表达式); const_cast<目标类型>(表达式); reinterpret_cast<目标类型>(表达式); dynamic_cast<目标类型>(表达式);
一、static_cast
用于内置数据类型之间的转换
除了语法不同,C和C++没有区别。
usingnamespacestd; intmain(intargc, char*argv[]) { intii=3; longll=ii; // 绝对安全,可以隐式转换,不会出现警告。doubledd=1.23; longll1=dd; // 可以隐式转换,但是,会出现可能丢失数据的警告。longll2= (long)dd; // C风格:显式转换,不会出现警告。longll3=static_cast<long>(dd); // C++风格:显式转换,不会出现警告。cout<<"ll1="<<ll1<<",ll2="<<ll2<<",ll3="<<ll3<<endl; }
用于指针之间的转换
C风格可以把不同类型的指针进行转换。
C++不可以,需要借助void *。
usingnamespacestd; voidfunc(void*ptr) { // 其它类型指针 -> void *指针 -> 其它类型指针double*pp=static_cast<double*>(ptr); } intmain(intargc, char*argv[]) { intii=10; double*pd1=ⅈ // 错误,不能隐式转换。double*pd2= (double*)ⅈ // C风格,强制转换。double*pd3=static_cast<double*>(&ii); // 错误,static_cast不支持不同类型指针的转换。void*pv=ⅈ // 任何类型的指针都可以隐式转换成void*。double*pd4=static_cast<double*>(pv); // static_cast可以把void *转换成其它类型的指针。func(&ii);
二、const_cast
static_cast不能丢掉指针(引用)的const和volitale属性,const_cast可以。
示例:
usingnamespacestd; intmain(intargc, char*argv[]) { intnum=4; constint*aa=# int*bb= (int*)aa; // C风格,强制转换,丢掉const限定符。int*cc=const_cast<int*>(aa); // C++风格,强制转换,丢掉const限定符。*bb=6; cout<<*bb<<endl; cout<<*cc<<endl; }
输出:
6 6
三、reinterpret_cast
static_cast不能用于转换不同类型的指针(引用)(不考虑有继承关系的情况),reinterpret_cast可以。
reinterpret_cast的意思是重新解释,能够将一种对象类型转换为另一种,不管它们是否有关系。
语法:reinterpret_cast<目标类型>(表达式);
<目标类型>和(表达式)中必须有一个是指针(引用)类型。
reinterpret_cast不能丢掉(表达式)的const或volitale属性。
应用场景:
reinterpret_cast的第一种用途是改变指针(引用)的类型。
reinterpret_cast的第二种用途是将指针(引用)转换成整型变量。整型与指针占用的字节数必须一致,否则会出现警告,转换可能损失精度。
reinterpret_cast的第三种用途是将一个整型变量转换成指针(引用)。
示例:
usingnamespacestd; voidfunc(void*ptr) { longlongii=reinterpret_cast<longlong>(ptr); cout<<"ii="<<ii<<endl; } intmain(intargc, char*argv[]) { longlongii=10; func(reinterpret_cast<void*>(ii)); }
输出:
4 4