Cpp学习13 第 10 章 类型转换、类型别名与类型推导

铁名_IronName Lv5

10.1 — 隐式类型转换

当需要一种数据类型,但提供了另一种数据类型时,编译器会自动执行隐式类型转换。
隐式类型转换 (也称为自动类型转换强制转换 )是由编译器在上下文中预期使用其他类型时自动执行的。C++ 中绝大多数类型转换都是隐式类型转换。

从 C++23 开始,共有 14 种不同的标准转换。这些转换大致可以分为 5 个大类。
表格,略。

如果编译器找不到可接受的类型转换,则编译将失败并出现编译错误。

即使编译器知道如何将 double 值转换为 int 值,但在使用大括号初始化时,不允许进行缩小范围的转换。

10.2 — 浮点数和整型提升

数据类型使用的位数称为其宽度。宽度较大的数据类型使用更多的位数,而宽度较小的数据类型使用较少的位数。

 numeric promotions 数值提升是指将某些较窄的数值类型(例如 char )转换为某些较宽的数值类型(通常是 int 或 double ),以便更高效地进行处理。
所有数值型转换都是保值的。 保值转换 (也称为安全转换 )是指每个可能的源值都可以转换为目标类型的相等值。
由于数值提升是安全的,编译器会根据需要自由地使用数值提升,并且不会发出警告。

(我好像没必要去区分是提升还是转换吧…)

10.3 — 数值转换

编译器通常不会对隐式保值转换发出警告。

略。

10.4 — 窄化转换、列表初始化和 constexpr 初始化器

在 C++ 中, 窄化转换是一种潜在的不安全的数值转换,其中目标类型可能无法容纳源类型的所有值。

由于 窄化转换 可能不安全且容易出错,因此应尽可能避免缩小转换范围。

最佳实践

如果需要执行缩小转换,请使用 static_cast 将其转换为显式转换。

从 constexpr 浮点类型转换为更窄的浮点类型不被视为缩小范围,即使会导致精度损失。

使用 constexpr 初始化器 列表初始化

这使我们能够避免:

  • 大多数情况下都必须使用字面后缀
  • 不得不使用 static_cast 来使初始化代码变得臃肿不堪。
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
// We can avoid literals with suffixes
unsigned int u { 5 }; // okay (we don't need to use `5u`)
float f { 1.5 }; // okay (we don't need to use `1.5f`)

// We can avoid static_casts
constexpr int n{ 5 };
double d { n }; // okay (we don't need a static_cast here)
short s { 5 }; // okay (there is no suffix for short, we don't need a static_cast here)

return 0;
}

这也适用于复制和直接初始化。

解释:
列表初始化({} 禁止“窄化转换”(Narrowing Conversion)。
想用列表初始化一个 float 时,通常不得不 写后缀。

如果编译器在编译时明确知道这个值的大小,并且确定它能被目标类型精确表示,那么它就不算“窄化转换”。
把值定义为 constexpr(编译期常量)时,编译器就知道它很安全,于是放心地让你直接赋给 float,不再要求写后缀或强转

10.5 — 算术转换

在 C++ 中,某些运算符要求其操作数类型必须相同。如果使用不同类型的操作数调用这些运算符,则其中一个或两个操作数将使用一组称为 “常规算术转换” 的规则隐式转换为匹配的类型。由常规算术转换规则生成的匹配类型称为操作数的公共类型 。

这就是避免使用无符号整数的主要原因之一——在算术表达式中将它们与有符号整数混用时,可能会导致意想不到的结果。而且编译器很可能甚至不会发出警告。

10.6 — 显式类型转换(强制转换)和 static_cast

CastDescriptionSafe?  安全的?
static_cast在编译时执行相关类型之间的类型转换。是的
dynamic_cast在多态(继承)层次结构中,对指针或引用执行运行时类型转换。是的
const_cast添加或删除常量。仅用于添加常量
reinterpret_cast将一种类型的位级表示重新解释为另一种类型
C-style casts执行  static_cast 、 const_cast 或 reinterpret_cast 的某种组合。

应该使用 static_cast 来转换大多数值。

static_cast 能更清晰地表明我们打算进行类型转换。虽然 static_cast比直接初始化列表的方式更冗长,但它使类型转换更容易被发现和查找。最终,这会让你的代码更安全、更易于理解。

10.7 — 类型定义和类型别名

Type aliases  类型别名

1
using Distance = double; // define Distance as an alias for type double

在现代 C++ 中,命名约定是将自定义的类型别名(或其他任何类型)以大写字母开头,且不加后缀。大写字母有助于区分类型名称与变量和函数名称(它们以小写字母开头),并防止它们之间发生命名冲突。

由于作用域是标识符的一个属性,类型别名标识符遵循与变量标识符相同的作用域规则:在代码块内定义的类型别名具有块级作用域,只能在该代码块内使用;而在全局命名空间中定义的类型别名具有全局作用域,可以在整个文件内使用。

Typedefs

typedef (即“类型定义”的缩写)是一种较早的类型别名创建方式。

1
2
3
// The following aliases are identical
typedef long Miles;
using Miles = long;

优先使用类型别名而不是类型定义。

使用类型别名实现平台无关编码:固定宽度整数类型 实际上只是各种基本类型的类型别名。

使用类型别名使复杂类型更易于阅读

到处都需要输入 std::vector<std::pair<std::string, int>> 这种类型,既繁琐又容易出错。使用类型别名要简单得多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <string> // for std::string
#include <vector> // for std::vector
#include <utility> // for std::pair

using VectPairSI = std::vector<std::pair<std::string, int>>; // make VectPairSI an alias for this crazy type

bool hasDuplicates(VectPairSI pairlist) // use VectPairSI in a function parameter
{
// some code here
return false;
}

int main()
{
VectPairSI pairlist; // instantiate a VectPairSI variable

return 0;
}

使用类型别名来记录值的含义

1
2
using TestScore = int;
TestScore gradeTest();

类型别名应主要用于那些能显著提升代码可读性或可维护性的情况。这既是一门科学,也是一门艺术。类型别名在代码的多个位置都能发挥作用时,比仅在少数位置使用时更有价值。

10.8 — 使用 auto 关键字的对象的类型推断

类型推导 (有时也称为类型推断 )是一项允许编译器从对象的初始化器推断对象类型的功能。

类型推断必须有可供推断的内容。

最佳实践

当对象的类型无关紧要时,请使用类型推导来定义变量。(承接 Lambda、迭代器、模板类型推导)

当您需要与初始化器类型不同的特定类型,或者当您的对象在需要明确类型的情况下使用时,请优先使用显式类型。

10.9 — 函数的类型推导

使用 auto 返回类型时,函数内的所有返回语句必须返回相同类型的值,否则会出错。

返回类型推断的最大优势在于,编译器推断函数的返回类型可以消除返回类型不匹配的风险(防止意外的转换)。

在其他情况下,函数的返回类型可能很长很复杂,或者并不那么显而易见。在这种情况下,可以使用 auto 简化。

返回类型推导的缺点

使用 auto 返回类型的函数必须先完整定义才能使用(仅进行前向声明是不够的)。

最佳实践

优先使用显式返回类型,而不是返回类型推导(除非返回类型不重要、难以表达或脆弱)。

尾随返回类型语法

1
2
3
4
auto add(int x, int y) -> int
{
return (x + y);
}

对于返回类型复杂的函数,在函数末尾添加返回类型可以使函数更易于阅读;
尾随返回类型语法可用于对齐函数名称,从而使连续的函数声明更易于阅读。

类型推导不能用于函数参数类型。

10.x — 第十章总结和测验

passed.

  • 标题: Cpp学习13 第 10 章 类型转换、类型别名与类型推导
  • 作者: 铁名_IronName
  • 创建于 : 2026-08-09 14:05:36
  • 更新于 : 2026-08-09 15:57:18
  • 链接: https://blog.ironname.top/2026/Cpp/Cpp学习13/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论