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;
}

这得到如下结果:

image


当隐式类型转换发生时

隐式类型转换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 int
10.2 -- Floating-point and integral promotion
10.2 -- 浮点数与整数的提升
Numeric promotions
数值提升
Floating point promotions
浮点提升
Converts float to double
将float提升为double
10.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节——函数重载解析与模糊匹配中将展示相关示例。

描述类型转换机制的完整规则既冗长又复杂,但大多数情况下类型转换“只需正常工作”即可。在后续课程中,我们将重点讲解标准转换的核心要点。若需处理特殊情况的细节,完整规则详见隐式转换的技术参考文档。

让我们开始吧!

posted @ 2026-03-02 16:05  游翔  阅读(0)  评论(0)    收藏  举报