C++丰富的基本类型允许根据需求选择不同的基本类型:11种整型和3种浮点型。在处理大量不同情况,尤其是对不同类型进行运算时,存在潜在的混乱。因此,C++支持自动执行很多类型转换:
- 将一种算数类型的值赋给另一种算数类型的变量时,C++将对值进行转换。
- 表达式中包含不同的类型时,C++将对值进行转换。
- 将参数传递给函数时,C++将对值进行转换。
1 初始化和赋值进行的转换
赋值后值将被转换为接收变量的类型。
有些转换是相对安全的:
- 将一个值赋给取值范围更大的类型通常不会导致什么问题,如short值赋给long变量,只是可能占用更多字节而已。
- 将零赋给bool变量时会转换成false,将非零值赋给bool变量时会转换成true。
还有些转换则会带来麻烦:
- 但将一个很大的long值赋给float变量时将降低精度,因为float只有6位有效数字。
- 将大浮点类型转换为较小的浮点类型,如double值转换为float,会降低精度甚至超出目标类型的取值范围,结果不确定。
- 将浮点型转换为整型,将会导致小数部分消失(截短),甚至超出目标取值范围,结果不确定(不同系统不一样)。
- 将较大的整型转换为较小的整型,可能会超出目标类型的取值范围,通常只复制右边的字节。
传统初始化行为和赋值相同。
C++11使用大括号{}初始化(即列表初始化)时对类型转换要求更严格。
- 列表初始化不允许缩窄,即变量的类型可能无法表示赋给它的值,如不允许将浮点型转换为整型。
- 在不同整型之间转换或将整型转换为浮点型可能被允许,条件是编译器知道目标变量能够正确地存储赋给它的值。
2 表达式中的转换
当同一个表达式中包含两种不同的算数类型时,有以下情况:
- 一些类型在出现时自动转换:在计算表达式时,C++将bool、char、unsigned char、signed char和short值转换为int,即整型提升,再将计算结果转换为接收变量类型赋给该变量。(int类型为计算最自然的类型,运算速度可能最快。)
- 还有一些其他整型提升:若short比int短,则unsigned short类型将被转换为int;若两种类型长度相同,则unsigned short类型将被转换为unsigned int。由此确保在对unsigned short进行提升时不会损失数据。
- 同样,wchar_t被提升成为int、unsigned int、long和unsigned long中第一个宽度足够存储wchar_t取值范围的类型。
- 还有些类型在与其他类型同时出现时将被转换:不同类型进行运算时,较小类型会转化为较大类型。
C++11版本的编译器校验表顺序:long double,double,float,整型提升。整型提升满足:
- 有符号整型级别:long long、long、int、short和signed char。无符号整级别与有符号相同。类型char、unsigned char和signed char的级别相同。wchar_t、char16_t和char32_t的级别与其底层类型相同。
- 如果两个操作数都是有符号的或无符号的,低级别的类型转换为高级别的。
- 如果一个有符号,一个无符号且级别高,则将有符号的操作数类型转换为无符号操作数所属类型;如果有符号类型的能表示无符号类型的所有取值,则无符号的操作数类型转换为有符号操作数所属类型;否则,将两个操作数都转换为有符号类型的无符号版本。
3 传递参数时的类型转换
传递参数时的类型转换通常由C++函数原型控制。
- 可以取消原型对参数转换的控制,但这样作并不明智。
- C++对char和short类型(signed和unsigned)应用整型提升。
- 为保证与传统C的兼容性,在将参数传递给取消原型对应参数传递控制的函数时, C++将float参数提升为double。
4 强制类型转换
C++允许通过强制类型转换机制显示地进行类型转换。
int haha = 1;
long haha1 = (long)haha; //来自C语言
long haha2 = long(haha); //纯粹的C++
static_cast<long> haha; //haha编程long类型
强制类型转换并不会改变haha变量本身,而是创建一个新的制定类型的值,可以在表达式中使用这个值。C++新格式使强制类型转换就像是函数调用。
C++还引入4个强制类型转换运算符。
- static_cast<>可用于将变量本身的值从一种类型转换为另一种类型。
- dynamic_cast<>
- const_cast<>
- reinterpret_cast<>
使用强制转换的原因:
- 可能有一些值被默认存为double类型,但要使用它们计算得到一个int类型的值。将两个double值求和再前值转换为int类型,与将两者先强制转换成int类型再求和得到的结果很可能是不同的。
- 使用一种格式的数据能满足不同的期望。
5 C++11的auto声明
auto让编译器能够根据初始值的类型推断变量的类型。
- auto本是一个C语言关键字,但很少使用。
- 在初始化声明中若使用auto而不指定变量类型,编译器吧变量的类型设置成与初始值相同。(容易误入歧途)
auto n = 100; //int
auto x = 1.5; //double
auto y = 1.3e12L; //long double
auto z = n; //int
处理复杂类型,如标准模块库(STL)中的类型时,这种自动类型推断便很有意义。
std::vector<double> scores;
std::vector<double>::iterator pv = scores.begin();
//第二句还可以表达为
auto pv = scores.begin();