在C/C++语言中用(type)value(在C++中还可以采用type(value))来进行显示类型转换(explicit type conversion),常常又被称为强制转换。这种转换的正确性完全掌握在程序员手中,传统上强制转换往往被过度使用,成为C++程序犯错的一个主要根源。
为了减少强制转换的副作用,并且在查错时使程序员能够快速定位强制转换,在标准C++中新增加了4个关键字*_cast,用来提倡一种全新的C++显示转换语法:
*_cast<type> (exotrssion)
1. static_cast(静态转换):用于明确定义良性和适度良性的转换,包括原来不需要采用强制转换的自动类型转换(包括无损的提升转换和可能丢失信息的窄化转换narrowing conversion),对后者编译器一般会提出告警。标准C++提倡对任何数据的类型转换(不论是自动的还是强制的),都采用新的*_cast显式类型转换方法。例如:
int i = 0x7fff;
long l;
float f;
char c;
// 典型的非强制转换(自动转换)
//传统方式
l = i;
f = i;
//提倡的新方式
l = static_cast<long>(i);
f = static_cast<float>(i);
//窄化转换,截断,强制转换
//传统方式,显示丢失精度的告警
i = l;
i = f;
c = i;
//不显示警告,传统强制转换
i = (int)l;
i = (int)f;
c = (char)i;
//提倡的新方式
i = static_cast<int>(i);
i = static_cast<int>(f);
c = static_cast<char>(i);
2. const_cast(常量转换),可将(同数据类型的)常量型const转换为非常型、将易变(volatile)型转换为非易变性。如果用于其他类型的转换,一般会产生一个编译错误。例如:
const int i = 0l
int *pi;
//错误
//pi = &i;
//被反对
pi = (int *)&i;
//完美做法,同类型常型和非常型转换
pi = const_cast<int *>(&i);
//错误,不同类型的常型和非常型转换
long *pl = const_cast<long *>(&i);
//完美做法,同类易变型和非易变型转换
volatile int k = 0;
int *pk = const_cast<int *>(&k);
3. dynamic_cast(动态转换),一种安全的向下类型转换操作没用于在一个类继承层次上向下移动。因为
每个派生类的基类都只有一个,而且派生类本身又包含了基类几乎所有的信息(private除外),所以向上的类型转换总是唯一的和安全的。而一个基类往往有多个派生类,而且派生类中一般会在基类的基础上添加了一些特有的数据和操作,所以向下的类型转换总是多态的和不安全的。
dynamic_cast提供了一种安全的向下类型转换操作,只有当类型转换是正确地并且转换取得成功,返回值才是所需要的指针,否则将返回0(空指针NULL),表示不正确的类型。
dynamic_cast虽然安全,但是运行时需要一定的开销,因此不提倡大量使用。如果已经能够确认转换的正确性,可以采用static_cast转换,无运行时开销。只有当你实在无法确定转换是否正确时,才需要dynamic_cast转换。
4. reinterpret_cast(重解释转换),转换一个指针为其他类型的指针,能够在非相关的类型之间转换。一种最有可能出问题的最不安全的类型转换。只是在下面的情形才需要使用这种类型转换:当需要使用时,所得到的东西已经不同了,为了使它能够用于原来的目的,必须再次把它转换回来。
const int sz = 100;
struct X {int a[sz];}
X x;
int *px = reinterpret_cast<int *>(&x); //为了初始化,先把结构转化为Int数组
for (int *i = px; i < px + sz; i ++)
{
*i = 0;
}
print(reinterpret_cast<X *>(px));
//重新转换成结构指针。
四种强制转换中,static_cast最常用,dynamic_cast最重要,const_cast也有用,reinterpret_cast很少用。