章节目录

隐式类型转换

本节阅读量:

类型转换简介

一个对象的值存储为二进制的序列,对象的数据类型告诉编译器如何将这些二进制解释为有意义的值。不同的数据类型可以以不同的方式表示“相同”的数字。例如,整数值3可以存储为二进制0000 0000 0000 0000 000 0000 0000 0011,而浮点值3.0可以存储为二进制0100 0000 0100 0000 0000 0000 0000。

那么当我们这样做时会发生什么呢?

1
float f{ 3 }; // 使用整数 3 去初始化浮点数

在这种情况下,编译器不能只将表示int值3的二进制数据复制到为浮点变量f分配的内存中。相反,它需要将整数值3转换为等效的浮点值3.0,然后将其存储在为f分配的存储器中。

从其它类型的值产生某种类型的新值的过程称为转换(conversion)。

类型转换可以以两种方式之一调用:隐式(根据编译器的需要)或显式(当程序员显式请求时)。本节中介绍隐式类型转换。


隐式类型转换

当需要一种类型的数据,但却提供了其它类型的数据时,编译器自动执行隐式类型转换(Implicit type conversion,也称为自动类型转换 automatic type conversion)。C++中的绝大多数类型转换都是隐式类型转换。例如,在以下所有情况下都会发生隐式类型转换:

  1. 使用其它数据类型的值初始化(或为其赋值)变量时:
1
2
double d{ 3 }; // int 3 隐式的转换为类型 double
d = 6; // int 6 隐式的转换为类型 double
  1. 当返回值的类型与函数声明的返回类型不同时:
1
2
3
4
float doSomething()
{
    return 3.0; // double 3.0 隐式的转换为 float
}
  1. 将某些二元运算符与不同类型的操作数一起使用时:
1
double division{ 4.0 / 3 }; // int 3 隐式的转换为类型 double
  1. 在if语句中使用非布尔值时:
1
2
3
if (5) // int 5 隐式的转换为类型 bool
{
}
  1. 当传递给函数的值与函数参数的类型不同时:
1
2
3
4
5
void doSomething(long l)
{
}

doSomething(3); // int 3 隐式的转换为类型 long

类型转换时会发生什么

当类型转换发生时(无论是隐式还是显式),编译器将确定它是否可以将值从当前类型转换为所需的类型。如果可以找到有效的转换,则编译器将生成所需类型的新值。请注意,类型转换不会更改要转换的值或对象的值或类型。

如果编译器找不到可接受的转换,则编译将失败,并出现编译错误。类型转换可能会因各种原因而失败。例如,编译器可能不知道如何在原始类型和所需类型之间转换值。或者,语句可能不允许某些类型的转换。例如:

1
int x { 3.5 }; // 大括号初始化,不允许有精度丢失的类型转换

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

在某些情况下,编译器可能无法确定几个可能的类型转换中的哪一个是最好的。我们将在后续函数重载解析和匹配中看到这样的例子。

那么编译器实际上如何确定它是否可以将值从一种类型转换为另一种类型呢?


标准转换

C++语言标准定义了如何将不同的基本类型(在某些情况下,复合类型)转换为其他类型。这些转换规则称为标准转换。

标准转换可大致分为4类,每个类别涵盖不同类型的转换:

  1. 数值提升
  2. 数值转换
  3. 算术转换
  4. 其他转换(包括各种指针和引用转换)

当需要类型转换时,编译器将查看是否存在可用于将值转换为所需类型的标准转换。编译器可以在转换过程中应用零个、一个或多个标准转换。

描述类型转换如何工作的完整规则集既冗长又复杂,并且在大多数情况下,类型转换“只是默默的生效”。在下面课程中,我们将介绍关于类型转换您需要了解的最重要的事情。如果某些不常见的情况需要更精细的细节,则在隐式转换的技术参考文档中详细介绍了完整的规则。

让我们开始吧!


9.6 第9章总结

上一节

10.1 数值提升

下一节