类型转换
何时发生隐式类型转换
在下面这些情况下,编译器会自动地转换运算对象的类型:
- 在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型。
- 在条件中,非布尔值转换成布尔类型
- 初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型
- 如果算术运算关系或关系运算的运算对象有多种类型,则需要转换成同一种类型。
- 函数调用时也会发生类型转换
1. 算术转换
算术转换的含义是把一种算术类型转换成另外一种算术类型。
2. 其他隐式类型转换
数组转换成指针
在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针:
int ia[10]; // 含有10个整数的数组
int* ip = ia; // ia转换成指向数组首元素的指针
当数组被用作decltype关键字的参数,或者作为取地址符(&)、sizeof及typeid等运算符的运算对象时,上述转换不会发生。同样的,如果用一个引用来初始化数组,上述转换也不会发生。
指针的转换
C++还规定了其他的指针转换方式,包括常量整数值0或者字面值nullptr能转换成任意指针类型;指向任意非常量的指针能转换成void*;指向任意对象的指针能转换成const void*。
转换成布尔类型
存在一种从算术类型或指针类型向布尔类型自动转换的机制。如果指针或算术类型的值为0,转换结果是false;否则转换结果是true
转换成常量
允许将指向非常量类型的指针转换成指向相应的常量类型的指针,对于引用也是这样。
3. 显式转换
有时我们希望显式地将对象强制转换成另外一种类型。例如,如果想在下面的代码中执行浮点数除法;
int i, j;
double slope = i/j;
就要使用某种方法将i或j显式地转换成double,这种方法称作强制类型转换(cast)。
注:虽然有时不得不使用强制类型转换,但这种方法本质上是非常危险的。
- 命名的强制类型转换
一个命名的强制类型转换具有如下形式:
cast-name<type>(expression);
其中,type是转换的目标类型,而expression是要转换的值。如果type是引用类型,则结果是左值。
cast-name是static_cast、dynamic_cast、const_cast和reinterpret_cast中的一种。cast-name指定了执行的是哪种转换。
static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
// 进行强制类型转换以便执行浮点数除法
double slope = static_cast<double>(j) / i;
static_cast对于编译器无法自动执行的类型转换也非常有用。例如,我么可以使用static_cast找回存在于void*指针中的值:
void* p = &d; // 正确:任何非常量对象的地址都能存入void*
// 将void*转换回初始的指针类型
double *dp = static_cast<double*>(p);
const_cast
const_cast只能改变运算对象的底层const:
const char *pc;
char *p = const_cast<char*>(pc); //正确,但是通过p写值是未定义的行为
对于将常量对象转换成非常量对象的行为,我们一般称其为“去掉const性质”。一旦我们去掉了某个对象的const性质,编译器就不能再阻止我们对该对象进行写操作了。如果对象本身不再是一个常量,使用强制类型转换获得写权限是合法的行为。然而如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果。
只有const_cast能改变表达式的常量属性,同样,const_cast不能用来改变表达式的类型。
const_cast常常用于有函数重载的上下文中。
reinterpret_cast
reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。
建议:避免强制类型转换,尤其是reinterpret_cast
评论