旧式的强制类型转换格式有两种:
type (expr);//函数形式的强制类型转换
(type) expr;//C语言风格的强制类型转换
C++提供了四种新的强制类型转换,其格式为:cast-name<type>(expression) type是转换的目标类型而expression是要转换的值。如果type是引用类型,则结果是左值。本文只介绍除dynamic_cast外的三种。
static_cast
任何具有明确定义的类型转换,都可以使用static_cast,但对于const对象来说,不能转换掉const性质。
int ival1 = 3, ival2 = 2;
double dval = static_cast<double>(ival1)/ival2;
当需要把一个较大的算术类型赋值给较小的类型时,static_cast非常有用。此时,强制类型转换告诉程序的读者和编译器:我们知道并且不在乎精度损失。一般来说,如果编译器发现一个较大的算数类型试图赋值给较小的类型,就会给出警告信息,但是当我们执行了显式地类型转换后,警告信息就会被关闭。
static_cast对于编译器无法自动执行的类型转换也非常有用。例如,我们可以使用static_cast找回存在于void*指针中的值:
double d = 3.24;
void *p = &d;
double *dp = static_cast<double*>(p);
当我们把指针存放在void*中,并且使用static_cast将其强制转换回原来的类型时,应该确保指针的值保持不变。也就是说,强制转换的结果将与原始的地址值相等,因此我们必须确保转换后所得得类型就是指针所指的类型。类型一旦不符,将产生未定义的后果。
const_cast
const_cast只能改变运算对象(只能是指针和引用)的底层const
#include <iostream>
int main (void)
{
char ch = 'a';
const char *pc = &ch;
char *p = const_cast<char*>(pc);
*p = 'c';
std::cout << *pc << std::endl;
return 0;
}
通过const_cast我们可以提取一个常量指针的地址来修改原来不可以修改的内容(假设我们不知道常量指针的初始值从何而来)。对于常量引用用法也是如此,但修改常量引用的const性质无法修改做到像修改常量指针一样修改本不可改的内容。其实使用const_cast去掉const属性并不是真的改变原类型的const属性,只是又提供了一个访问接口而已,对于指针,你可以通过这个接口来改变对象内容。
对于将常量对象转换成非常量对象的行为,一般称为“去掉const性质(cast away the const)”。一旦我们去掉了某个对象的const性质,编译器就不再阻止我们队该对象进行写操作了。如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。然而如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果。
#include <iostream>
int main (void)
{
const int a = 100;
int *p = const_cast<int*>(&a);
*p = 200;
std::cout << "&a=" << &a << std::endl;
std::cout << "p=" << p << std::endl;
std::cout << "a1=" << a << std::endl;
std::cout << "a2=" << *&a << std::endl;
std::cout << "*p=" << *p << std::endl;
return 0;
}
这是一个有趣的程序,运行程序可以发现直接输出a和通过地址间接输出a居然得到不同的值,直观感觉是同一个地址存放了两个不同的值一样。这就是使用const_cast带来的副作用,由于const变量的存储与普通局部变量不同,而C++标准并未定义使用强制类型转换对常量对象执行写操作后产生的后果,因为上面的程序完全不是const_cast设计的初衷。const_cast的目的在于某些变量原本不是const的,但出于安全性或其他特殊原因使用了一个const引用或指针指向了一个本来不是const的对象,在实际使用中需要修改。
reinterpret_cast
reinterpret_cast通常为运算对象位模式提供较低层次上的重新解释。
int ival = 3;
int *ip = &ival;
char *pc = reinterpret_cast<char*>(ip);//用一个char指针存放一个int指针的值(地址)
reinterpret_cast做的工作就是比特位映射,在刚才的几行代码中相当于将ip存放内容的比特位复制到了pc中去。使用reinterpret_cast必须牢记所指的真实对象时一个int类型而非char类型,如果把pc当作普通字符指针使用将导致未定义的后果。
reinterpret_cast的使用需要很谨慎,因为对任意类型的转换在任何时候都是非常危险的(就像void*),但在一些特殊场景renterpret_cast又能发挥大作用,比如在需要精细控制内存布局以实现自定义的高性能数据结构、需要直接操作内存的地方(比如网络封包解包、数据压缩加解密算法等)、需要和C代码接口的地方等。
根据所涉及类型的不同,旧式的强制类型转换分别具有与static_cast、const_cast或reinterpret_cast相似的行为。与命名的强制类型转换相比,旧式的强制类型转换从表现形式上来说不那么清晰明了,所以一旦转换过程出现问题,追踪起来也更加困难
本文部分内容摘自《C++Primer(第5版)》