10-1 隐式类型转换
我们在第4.12课——类型转换与static_cast介绍中引入了类型转换。总结一下那节课中最重要的要点:
- 将数据从一种类型转换到另一种类型的过程称为“类型转换”。
- 当需要一种数据类型但提供了不同的数据类型时,编译器会自动执行隐式类型转换。
- 通过使用cast运算符(如static_cast)请求显式类型转换。
- 转换不会改变被转换的数据。相反,转换过程使用这些数据作为输入,生成转换后的结果。
- 当将一个值转换为另一种类型的值时,转换过程会生成一个目标类型的临时对象,用于存储转换结果。
在本章的前半部分,我们将更深入地探讨类型转换的工作原理。本课我们将从隐式转换开始,接下来的第10.6课将从显式类型转换(casting)开始——显式类型转换(casting)和static_cast。由于类型转换在各个地方都有使用,了解需要转换时底层发生的事情非常重要。这些知识对于理解重载函数(即可能与其他函数名称相同的函数)的工作原理也很重要。
作者注
本章我们将重点探讨一种值向其他类型的值的转换。在介绍前置主题(如指针、引用、继承等)后,我们会介绍其他类型的转换。
为什么需要转换
对象的值以比特序列形式存储,对象的数据类型告诉编译器如何将这些比特解释为有意义的值。不同的数据类型可能以不同方式表示“相同”的值。例如,整数值 3 可能以二进制 0000 0000 0000 0000 0000 0000 0000 0011 存储,而浮点值 3.0 可能存储为二进制 0100 0000 0100 0000 0000 0000 0000 0000。
那么,当我们做这种事时会发生什么?
float f{ 3 }; // initialize floating point variable with int 3
在这种情况下,编译器不能仅仅将用于表示整数值3的位复制到分配给浮点变量f的内存中。如果真的这么做,那么当 f(类型为 float)被计算时,这些位会被解释为浮点而不是整数,谁知道最终会得到什么浮点值!
顺便说一句......
以下程序实际上将整数值3打印为当作浮点数:
#include <iostream>
#include <cstring>
int main()
{
int n { 3 }; // here's int value 3
float f {}; // here's our float variable
std::memcpy(&f, &n, sizeof(float)); // copy the bits from n into f
std::cout << f << '\n'; // print f (containing the bits from n)
return 0;
}
这得到如下结果:

当隐式类型转换发生时
隐式类型转换Implicit type conversion(也称为自动类型转换automatic type conversion或强制转换coercion)由编译器在预期其他类型的上下文中提供某种表达式时自动执行。C++ 中绝大多数类型的转换都是隐式的类型转换。例如,隐式类型转换发生在以下所有情况下:
使用不同数据类型的值初始化(或赋值)变量时:
double d{ 3 }; // int value 3 implicitly converted to type double
d = 6; // int value 6 implicitly converted to type double
当函数返回值类型与声明的返回类型不一致时:
float doSomething()
{
return 3.0; // double value 3.0 implicitly converted to type float
}
使用特定二元运算符处理不同类型操作数时:
double division{ 4.0 / 3 }; // int value 3 implicitly converted to type double
在if语句中使用非布尔值时:
if (5) // int value 5 implicitly converted to type bool
{
}
当函数形参类型与实际传入实参类型不匹配时:
void doSomething(long l)
{
}
doSomething(3); // int value 3 implicitly converted to type long
那么编译器究竟如何实现值的类型转换?
标准转换
作为核心语言的一部分,C++标准定义了一组称为“标准转换standard conversions”的转换规则。这些规则规定了各类基础类型(及某些复合类型,包括数组、引用、指针和枚举)在同类组内如何转换为其他类型。
截至C++23,共有14种标准转换,大致可归为5类:
| Category 类别 |
Meaning 含义 |
Link 链接 |
|---|---|---|
| Numeric promotions 数值提升 |
Conversions of small integral types to int or unsigned int, and of float to double. 将小整数类型转换为int或unsigned int,将float转换为double。 |
10.2 -- Floating-point and integral promotion 10.2 -- 浮点数与整数提升 |
| Numeric conversions 数值转换 |
Other integral and floating point conversions that aren't promotions. 除提升外的其他整数与浮点转换。 |
10.3 -- Numeric conversions 10.3 -- 数值转换 |
| Qualification conversions 限定符转换 |
Conversions that add or remove const or volatile. 添加或移除const/volatile限定符的转换。 |
|
| Value transformations 值转换 |
Conversions that change the value category of an expression 改变表达式值类别的转换 |
12.2 -- Value categories (lvalues and rvalues) 12.2 -- 值类别(左值与右值) |
| Pointer conversions 指针转换 |
Conversions from std::nullptr to pointer types, or pointer types to other pointer types std::nullptr与指针类型间转换,或指针类型间相互转换 |
例如,将 int 值转换为 float 值属于数值转换范畴,因此编译器执行此类转换时,只需应用 int 到 float 的数值转换规则即可。
数值转换和数值提升是这些范畴中最关键的部分,后续课程将详细探讨。
对于进阶读者
标准转换完整列表如下:
Category
类别Standard Conversion
标准转换Description
描述Also See
另见Value transformation
值转换Lvalue-to-rvalue
左值转右值Converts lvalue expression to rvalue expression
将左值表达式转换为右值表达式12.2 -- Value categories (lvalues and rvalues)
12.2 -- 值类别(左值与右值)Value transformation
值转换Array-to-pointer
数组转指针Converts C-style array to pointer to first array element (a.k.a. array decay)
将C风格数组转换为指向数组首元素的指针(即数组衰变)17.8 -- C-style array decay
17.8 -- C 风格数组衰变Value transformation
值转换Function-to-pointer
函数转指针Converts function to function pointer
将函数转换为函数指针20.1 -- Function Pointers
20.1 -- 函数指针Value transformation
值转换Temporary materialization
临时对象化Converts value to temporary object
将值转换为临时对象Qualification conversion
修饰符转换Qualification conversion
修饰符转换Adds or removes const or volatile from types
在类型前添加或移除const/volatile修饰符Numeric promotions
数值提升Integral promotions
整数提升Converts smaller integral types to int or unsigned int
将较小整数类型提升为int或unsigned int10.2 -- Floating-point and integral promotion
10.2 -- 浮点数与整数的提升Numeric promotions
数值提升Floating point promotions
浮点提升Converts float to double
将float提升为double10.2 -- Floating-point and integral promotion
10.2 -- 浮点数与整数的提升Numeric conversions
数值转换Integral conversions
整数转换Integral conversions that aren't integral promotions
非提升类型的整数转换10.3 -- Numeric conversions
10.3 -- 数值转换Numeric conversions
数值转换Floating point conversions
浮点转换Floating point conversions that aren't floating point promotions
非浮点提升的浮点转换10.3 -- Numeric conversions
10.3 -- 数值转换Numeric conversions
数值转换Integral-floating conversions
整数-浮点转换Converts integral and floating point types
将整数和浮点类型进行转换10.3 -- Numeric conversions
10.3 -- 数值转换Numeric conversions
数值转换Boolean conversions
布尔转换Converts integral, unscoped enumeration, pointer, or pointer-to-member to bool
将整数、无作用域枚举、指针或成员指针转换为布尔值4.10 -- Introduction to if statements
4.10 -- if 语句简介Pointer conversions
指针转换Pointer conversions
指针转换Converts std::nullptr to pointer, or pointer to void pointer or base class
将 std::nullptr 转换为指针,或将指针转换为 void 指针或基类指针Pointer conversions
指针转换Pointer-to-member conversions
成员指针转换Converts std::nullptr to pointer-to-member or pointer-to-member of base class to pointer-to-member of derived class
将 std::nullptr 转换为成员指针或将基类的成员指针转换为派生类的成员指针Pointer conversions
指针转换Function pointer conversions
函数指针转换Converts pointer-to-noexcept-function to pointer-to-function
将noexcept函数指针转换为函数指针
类型转换可能失败
当调用类型转换(无论隐式或显式)时,编译器将判断能否将值从当前类型转换为目标类型。若存在有效转换,编译器将生成目标类型的全新值。
若编译器无法找到可接受的转换,编译将因编译错误而失败。类型转换可能因多种原因失败。例如,编译器可能无法确定原始类型与目标类型之间的值转换方式。
例如:
int main()
{
int x { "14" };
return 0;
}
由于字符串字面量“14”不存在标准转换为int的途径,编译器将报错。例如GCC会输出错误:prog.cc:3:13: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]。
在其他情况下,特定特性可能禁止某些类别的转换。例如:
int x { 3.5 }; // brace-initialization disallows conversions that result in data loss
尽管编译器知道如何将double值转换为int值,但在使用大括号初始化时禁止窄化转换。
有时编译器也可能无法确定多种类型转换方案中哪一种最优。第11.3节——函数重载解析与模糊匹配中将展示相关示例。
描述类型转换机制的完整规则既冗长又复杂,但大多数情况下类型转换“只需正常工作”即可。在后续课程中,我们将重点讲解标准转换的核心要点。若需处理特殊情况的细节,完整规则详见隐式转换的技术参考文档。
让我们开始吧!

浙公网安备 33010602011771号