4.4 类型转换
C++自动执行的类型转换:
1、将一种算术类型的值赋给另一种算术类型的变量时,C++将对值进行转换
2、表达式中包含不同的类型时,C++将对值进行转换
3、将参数传递给函数时,C++将对值进行转换
4.4.1 初始化和赋值进行的转换
C++允许将一种类型的值赋给另一种类型的变量。这样做时,值将被转换为接收变量的类型。
例:
int a = 10;
long b = a ;
将一个值赋给值取值范围更大的类型通常不会导致什么问题。反之则有可能会带来麻烦,如下表所示:
转换 | 潜在问题 |
将较大的浮点类型转换为较小的浮点类型,如将double转换为float | 精度(有效位数)降低,值可能超出目标类型的取值范围,在这种情况下,结果将是不确定的 |
将浮点类型转换为整型 | 小数部分丢失,原来的值可能超出目标类型的取值范围,在这种情况下,结果将是不确定的 |
将较大的整型转换为较小的整型,如将long转换为short | 原来的值可能超出目标类型的取值范围,通常只复制右边的字节 |
将0赋给bool类型的变量时,将被转换为false;而非零值将被转换为true。
将浮点值赋给整型将导致两个问题。首先,将浮点值转换为整型会将数字截短(除掉小数部分)。其次,float值对于int变量来说可能太大了。
传统初始化的行为与赋值相同。
4.4.2 以{}方式初始化时进行的转换
C++11将使用大括号的初始化称为列表初始化(list-initialization) ,因为这种初始化常用于给复杂的数据类型提供值列表。它对类型转换的要求更严格。具体地说,列表初始化不允许缩窄(narrowing) ,即变量的类型可能无法表示赋给它的值。例如,不允许将浮点型转换为整型。在不同的整型之间转换或将整型转换为浮点型可能被允许,条件是编译器知道目标变量能够正确地存储赋给它的值。例如,可将long变量初始化为int值,因为long总是至少与ing一样长;相反方向的转换也可能被允许,只要int变能够存储赋给它的long常量:
#include <iostream>
int main()
{
using namespace std;
cout.setf(ios_base::fixed, ios_base::floatfield);
float a = 3.12f;
int b = a;
int c(20);
cout << "a = " << a << " b = " << b << " c = "<<c<< endl;
cout << endl;
const int code = 66;
int x = 66;
//char c1{ 31325 }; // narrowing, not allowed
char c2 = { 66 }; // allowed because char can hold 66
char c3{ code };// ditto
//char c4 = { x };//x的值为66,但在编译器看来,x是一个变量,其值可能很大。
x = 31325;
char c5 = x; // allowed by this form of initialization
return 0;
}
4.4.3 表达式中的转换 ☆
自动转换:
C++执行两种自动转换:首先,一些类型在出现时便会自动转换;其次,有些类型在其他类型同时出现在表达式中时将被转换。
整型提升:
C++将bool、char、unsigned char、signed char和short值转换为int。具体地说,true转换为1,false转换为0。这些转换被称为整型提升。
C++11版本的校验表, 编译器将依次查阅该列表。
(1)如果有一个操作数的类型是long double,则将另一个操作数转换为long double。
(2)否则,如果有一个操作数的类型是double,则将另一个操作数转换为double。
(3)否则,如果有一个操作数的类型是float,则将另一个操作数转换为float。
(4)否则,说明操作数都是整型,因此执行整型提升。
(5)在这种情况下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别此另一个低,则转换为级别高的类型。
(6)如果一个操作数为有符号的,另一个操作数为无符号的,且无符号操作数的级别比有符号操作数高,则将有符号操作数转换为无符号操作数所属的类型。
(7)否则,如果有符号类型可表示无符号类型的所有可能取值,则将无符号操作数转换为有符号操作数所属的类型。
(8)否则,将两个操作数都转换为有符号类型的无符号版本。
整型级别的转换:
有符号整型按级别从高到低依次为long long、long、int、short和signed char。无符号整型的排列顺序与有符号整型相同。类型char、 signed char和unsigned char的级别相同。类型bool的级别最低。wchar_t、char16_t和char32_t的级别与其底层类型相同。
4.4.4 传递参数时的转换
传递参数时的类型转换通常由C++函数原型控制。如果取消原型对参数传递的控制,C++将对char和short类型(signed和unsigned)应用整型提升。另外,为保持与传统C语言中大量代码的兼容性,在将参数传递给取消原型对参数传递控制的函数时,C++将float参数提升为double。
4.4.5 强制类型转换
C++允许通过强制类型转机制显式地进行类型转换。
强制类型转换的格式有两种:
(1) (typeName) value //来自C语言
(2) typeName (value) //C++,想法是,要让强制类型转换就像是函数调用。
强制类型转换不会修改value变量本身,而是创建一个新的、指定类型的值,可以在表达式中使用这个值。
4.4.6 auto声明
C++11新增了一个工具,让编译器能够根据初始值的类型推断变量的类型。
auto n = 100;
auto x = 1.5;
auto y = 1.3e12L;
习题:
auto fract = 8.25f / 2.5 ;问fract是什么类型?
答案:double。
在默认情况下,像8.24、2.4E8这样的浮点常量都属于double类型。如果希望常量为float类型,要使用f或F后缀。