C++的几种强制类型转换
有时我们希望显式地将对象强制类型转换成另外一种类型。例如,如果想在下面的代码中执行浮点数除法:
int i, j;
double slope = i / j;
就要使用某种方法将i和/或j显式地转换成double,这种方法称作强制类型转换。
命名的强制类型转换
一个命名的强制类型转换具有如下形式:
cast_name<type>(expression);
其中,type是转换的目标类型而expression是要转换的值。如果type是引用类型,则结果是左值,cast-name是static_cast, dynamic_cast, const_cast和reinterpret_cast中的一种。dynamic_cast支持运行时类型识别。cast-name指定了执行的是哪种转换。
static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_const。
例如,通过将一个运算对象强制转换成double类型就能使表达式执行浮点数除法:
double slope = static_cast<double>(j) / i;
当需要把一个较大的算术类型赋值给较小的类型时,static_cast非常有用。此时,强制类型转换告诉程序的读者和编译器:我们知道并且不在乎潜在的精度损失。一般来说,如果编译器发现一个的算术类型试图赋值给较小的类型,就会给出警告信息;但是当我们执行了显式的类型转换后,警告信息就会被关闭了。
static_cast对于编译器无法自动执行的类型转换也非常有用。例如,我们可以使用static_cast找回存在于void*指针中的值:
void *p = &d; //正确:任何非常量对象的地址都能存入void*
//正确:将void*转换回初始的指针类型
double *dp = static_cast<double*>(p);
当我们把指针存放在void*中,并且使用static_cast将其强制转换回原来的类型时,应该确保指针的值保持不变。也就是说,强制转换的结果将与原始的地址值相等,因此我们必须确保转换后所得的类型就是指针所指的类型。类型一旦不符,将产生未定义的后果。
const_cast
const_cast只能改变运算对象的底层const
const char *pc;
char *p = const_cast<char*> (pc); //正确:但是通过p写值是未定义的行为
对于将常量对象转化为非常量对象的行为,我们一般称之为”去掉const性质(cast away the const)“。一旦我们去掉了某个对象的const性质,编译器就不再阻止我们对该对象进行写操作了。如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。然而如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果。
只有 const_cast能改变表达式的常量属性,使用其他形式的命名强制类型转换改变表达式的常量属性都将引发编译器错误。同样地,也不能用const_cast改变表达式的类型:
const char *cp; //错误:static_cast不能转换掉const性质 char* q = static_cast<char*> (cp); static_cast<string> (cp); //正确,字符串字面值转换成string类型 const_cast<string>(cp); //错误,const_cast只改变常量属性
总结来说:const_cast只能改变底层const,即它只能改变对象或引用的const属性,不能改变对象的const属性。const_cast即可以添加const性质,也可以删除const性质。
reinterpret_cast
reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。举个例子,假设有如下的转换:
int *ip;
char *pc = reinterpret_cast<char*>(ip);
我们必须牢记pc所指的真实对象是int而非字符,如果把pc当成一个普通的字符指针使用就可能在运行时发生错误。例如:
string str(po);
可能导致异常的运行时行为。
使用reinterpret_cast是非常危险的,用pc初始化的例子很好地证明了这一点。其中的关键问题是类型改变了,但编译器没有给出任何警告或者错误的提示信息。当我们用一个int的地址初始化pc时,由于显式地声称这种转换合法,所以编译器不会发出任何警告或错误信息。接下来再使用pc时就会认定它的值是char*类型,编译器没法知道它实际存放的是指向int的指针。
dynamic_cast
只用于对象的指针和引用. 当用于多态类型时,它允许任意的隐式类型转换以及相 反过程. 不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast 会检查操作是否有效. 也就是说, 它会检查转换是否会返回一个被请求的有效的完整对象。检测在运行时进行. 如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL. 对于引用 类型,会抛出bad_cast异常 .