10-x 第十章总结与测验
能坚持到这里很棒。标准转换规则相当复杂——不必担心无法理解每个细节。
章节回顾
将值从一种数据类型转换为另一种数据类型的过程称为类型转换type conversion。
隐式类型转换implicit type conversion(也称自动类型转换automatic type conversion或强制转换coercion)发生在预期某种类型的数据时,却被提供不同类型数据的情况。若编译器能确定两种类型间的转换方式,则会自动执行转换;若无法确定,则会报编译错误。
C++语言定义了基础类型间的多项内置转换(以及部分高级类型的转换),称为标准转换standard conversions。这些转换包括数值提升、数值转换和算术转换。
数值提升numeric promotion是指将特定较小数值类型转换为特定较大数值类型(通常为 int 或 double),以便 CPU 能处理与处理器自然数据尺寸匹配的数据。数值提升包含整数提升和浮点提升两种形式。数值提升具有值保留特性value-preserving,即不会导致数值或精度损失。并非所有拓宽转换都属于提升。
数值转换numeric conversion是指基本类型间不属于数值提升的类型转换。窄化转换narrowing conversion属于数值转换,可能导致数值或精度损失。
在C++中,某些二元运算符要求其操作数类型一致。若提供不同类型的操作数,则会根据称为常规算术转换usual arithmetic conversions的规则集,将一个或两个操作数隐式转换为匹配类型。
显式类型转explicit type conversion换发生于程序员通过强制转换显式请求转换时。强制转换cast代表程序员要求执行显式类型转换。C++支持五种强制转换类型:C风格强制转换C-style casts、静态强制转换static casts、const强制转换const casts、动态强制转换dynamic casts和reinterpret强制转换reinterpret casts。通常应避免使用C风格转换、const转换和reinterpret转换。static_cast用于将值从一种类型转换为另一种类型,是C++中最常用的转换方式。
类型定义typedef和类型别名type aliases允许程序员为数据类型创建别名。这些别名并非新类型,其行为与被别名类型完全一致。类型别名不提供任何类型安全保障,需谨慎避免将别名与原始类型混淆。
auto 关键字具有多重用途:首先可用于类型推断type deduction(也称类型推导type inference),即根据初始化表达式推断变量类型。类型推断会忽略 const 和引用修饰符,若需保留这些修饰符请手动添加。
Auto 也可用作函数返回类型,让编译器根据函数的返回语句推断其返回类型,但普通函数应避免使用此方式。Auto 作为尾随返回语法trailing return syntax的一部分使用。
测验时间
问题 #1
下列各例中发生何种类型转换?有效答案包括:无需转换、数值提升、数值转换、因窄化转换导致编译失败。假设 int 和 long 均为 4 字节类型。
int main()
{
int a { 5 }; // 1a
int b { 'a' }; // 1b
int c { 5.4 }; // 1c
int d { true }; // 1d
int e { static_cast<int>(5.4) }; // 1e
double f { 5.0f }; // 1f
double g { 5 }; // 1g
// Extra credit section
long h { 5 }; // 1h
float i { f }; // 1i (uses previously defined variable f)
float j { 5.0 }; // 1j
}
1a) 显示答案
无需转换
1b) 显示答案
将字符‘a’数值提升为整型
1c) 显示答案
由于窄化转换,无法编译
1d) 显示答案
将布尔值 true 提升为整数类型
1e) 显示答案
将双精度浮点数5.4转换为整型
1f) 显示答案
将浮点数强制提升为双精度类型
1g) 显示答案
将整型数转换为双精度浮点数
1h) 显示答案
将整型数转换为长整型数(此转换虽简单,但仍属于数值转换操作)
1i) 显示答案
由于从 double 到 float 的窄化转换,无法编译
1j) 显示答案
将double数值转换为float(此操作在5.0版本中被允许,因为constexpr且结果值在float的取值范围内)
问题 #2
2a) 更新以下程序,使用类型别名处理度和弧度值:
#include <iostream>
namespace constants
{
constexpr double pi { 3.14159 };
}
double convertToRadians(double degrees)
{
return degrees * constants::pi / 180;
}
int main()
{
std::cout << "Enter a number of degrees: ";
double degrees{};
std::cin >> degrees;
double radians { convertToRadians(degrees) };
std::cout << degrees << " degrees is " << radians << " radians.\n";
return 0;
}
显示答案
#include <iostream>
namespace constants
{
constexpr double pi{ 3.14159 };
}
using Degrees = double;
using Radians = double;
Radians convertToRadians(Degrees degrees)
{
return degrees * constants::pi / 180;
}
int main()
{
std::cout << "Enter a number of degrees: ";
Degrees degrees{};
std::cin >> degrees;
Radians radians{ convertToRadians(degrees) };
std::cout << degrees << " degrees is " << radians << " radians.\n";
return 0;
}
2b) 根据前题答案中度与弧度的定义,说明下列语句能否编译:
radians = degrees;
显示答案
它可以编译。radians 的类型是 Radians,这是 double 的类型别名。degrees 的类型是 Degrees,同样是 double 的类型别名。因此这只是将 double 值赋给 double 类型的变量。

浙公网安备 33010602011771号