8.x - 小结与测试 - 类型转换和函数重载
学完咯!本章的主题(特别是类型别名、重载函数和函数模板)在 C++ 标准库中随处可见。我们还有一章要讲(介绍复合类型),然后我们将准备好深入研究标准库中最有用的部分!
复习
将一种数据类型转换为另外一种数据类型的过程叫做类型转换。
当需要一种数据类型,但提供了不同的数据类型时,则会执行隐式类型转换(也称为自动类型转换或强制转换)。如果编译器能够找到两种类型之间进进行隐式类型转换的规则,则它会执行隐式类型转换,否则就会产生编译报错。(8.1 - 隐式类型转换)
C++ 语言定义了许多基本类型之间的内置转换方式(以及一些更高级的类型的转换),称为标准转换。其中包括数值提升、数值转换和算数转换
数值提升(8.2 - 浮点数和整型提升)是将较小的数值类型转换为较大的数值类型(通常为 int
或 double
),这样CPU就可以对与处理器自然数据大小相匹配的数据进行操作。数值提升包括整数提升和浮点提升。数字提升是保值的,这意味着不会丢失值或值的精度。
数值转换(8.3 - 数值转换)数值转换是基本类型之间的类型转换,而不是数值提升。收缩转换可能会导致值或精度的损失。
在C++中,某些二元操作符要求它们的操作数具有相同的类型。如果提供了不同类型的操作数,则使用一组称为普通算术转换(8.4 - 算术转换)规则将其中一个或两个操作数隐式转换为匹配类型。
当程序员显式地通过 cast 来进行类型转换时,称为显式类型转换(8.5 - 显式类型转换和static_cast)。C++支持5种类型强制转换:C风格类型转换、静态类型转换、const 类型转换、动态类型转换和重新解释类型转换。一般来说,你应该避免使用"C风格类型转换”、“const类型转换”和“重新解释类型转换”。static_cast
用于将一个值从一种类型转换为另一种类型,它是目前C++中被最多使用的强制转换。
typedef 和类型别名允许程序员为数据类型创建别名。这些别名不是新类型,并且与原类型的操作相同。Typedefs 和类型别名不提供任何类型安全机制,需要注意的是,不要假定类型别名和其原类型是有区别的。
auto
关键字有很多用途。首先,auto
可用于进行类型推断(8.7 - 使用 auto 关键字进行类型推断),它将从变量的初始化值推断出变量的类型。但是,类型推断会丢弃 const 和引用,所以如果需要,请确保将它们添加回来。
auto
也可以用作函数返回类型的推断(8.8 - 函数的类型推断),编译器可以从函数的return
语句中推断出函数的返回类型,不过对于普通函数应该避免这样做。auto
还被用作后置返回值类型语法。
函数重载(8.9 - 函数重载)允许我们使用相同的名称创建多个函数,只要每个相同名称的函数具有不同的形参类型集合即可(或者可以用其他方式区分函数)。这样的函数称为重载函数(或简称重载)。返回类型不能被用来进行重载函数的区分。
在解析重载函数时(8.10 - 函数重载和区分),如果没有找到精确匹配,编译器将优先选择可以通过数值提升匹配的重载函数,而不是那些需要数值转换的重载函数。当对已重载的函数进行函数调用时,编译器将尝试根据函数调用中使用的参数将函数调用与适当的重载匹配。这被称为重载解析。
当编译器发现两个或多个函数可以将函数调用与重载函数匹配,但无法确定哪一个是最好的时,就会出现不明确匹配(8.11 - 函数重载解析和不明确匹配)。
默认实参是为函数形参提供的默认值(8.12 - 默认参数)。带默认实参的形参必须始终是最右边的形参,并且在解析重载函数时不使用它们来区分函数。
函数模板(8.13 - 函数模板)允许我们创建一个类似函数的定义,作为创建相关函数的模式。在函数模板中,我们使用模板类型作为以后要指定的任何类型的占位符。告诉编译器我们正在定义一个模板并声明模板类型的语法称为模板形参声明。
从函数模板(使用模板类型)创建函数(使用特定类型)的过程简称为函数模板实例化(或实例化)。当这个过程由于函数调用而发生时,它被称为“隐式实例化”。一个实例化的函数被称为函数实例(或简称实例,有时也称为模板函数)。
模板实参推导允许编译器从函数调用的实参推导出应该用于实例化函数的实际类型。模板参数推导不进行类型转换。
模板类型有时被称为泛型类型,使用模板编程有时被称为泛型编程。
在C++ 20中,当 auto
关键字在普通函数中用作形参类型时,编译器会自动将函数转换为函数模板,每个 auto
形参都成为一个独立的模板类型形参。这种创建函数模板的方法称为缩写函数模板。