C++兼容了C的类型转换方式,可以在C++代码中使用C风格类型转换,尤其是在大量的把C++当成C来用的项目里面,非常普遍。Modern C++提供了诸如static_cast
, dynamic_cast
, reinterpret_cast
, const_cast
的类型转换方式,在逐个讲清楚之前,先回顾一下常用的C风格的类型转换方式。
下面总结C-Style的类型转换存在的几个问题:
void foo() {
int a = 7;
int b = 4;
std::cout << a / b << std::endl;
//期待得到浮点结果的话
std::cout << double(a) / b << std::endl; //(1)
std::cout << double(a) / double(b) << std::endl; //(2)
}
上面代码中(2)是显式类型转换,就是告诉编译器要把a和b转换为double类型,而(1)是隐式类型转换(implicit convension
),在(1)里面,b被隐式转为了double类型。
隐式类型转换带来了一个常见的问题:丢失信息。通常发生在把bit width更大的变量转换到bit width更小的变量时,例如:
void bar(char c) {
// do somthing
}
void foo() {
int a = 300;
bar(a);
}
//char 的bit width容纳不下int变量的值
//所以这里就会在类型转换时丢失掉多出部分的bit信息
顺着上例,举一个负数比较的例子:
void foo() {
int a = -1234567;
unsigned int b = 5;
if (a > b) { //(1)
std::cout << "???" << std::endl;
}
}
在(1)这里发生了implicit convension,a被转换为了unsigned int类型,所以导致了进入if分支。只要学过计算机组成原理,自然知道正数和负数在二进制下是如何表达的,应该不难理解。
除此之外,还有很多实践中常见的隐式转换带来的问题,这里不再一一列举。
本质上,都是和bit width相关。
所以使用C-Style的类型转换,程序员需要注意:
- 清楚知道转换前后的两种类型的bitwidth,确保不会丢失信息
- 书写显式类型转换的代码,尽量避免使用隐式转换(非常不容易,这往往会发生在不经意之间,虽然很多问题都可以通过开启编译告警来提前发现-Wall,但是太多的人忽视编译器的警告)
Modern C++增加了开头提到的几种方法进行类型转换,在使用Modern C++写代码的时候,应该尽量避免使用C-Style的转换方式。