11-2 函数重载的区分
在上一课(11.1——函数重载介绍)中,我们介绍了函数重载的概念。该机制允许创建多个同名函数,前提是每个同名函数的参数类型不同(或函数可通过其他方式区分)。
本节课我们将深入探讨如何区分重载函数。若重载函数未被正确区分,编译器将报出编译错误。
本节将深入探讨重载函数的区分机制。若重载函数未正确区分,编译器将报错。
重载函数的区分方式
| Function property 函数属性 |
Used for differentiation 区分依据 |
Notes 备注 |
|---|---|---|
| Number of parameters 形参数量 |
Yes 是 |
|
| Type of parameters 形参类型 |
Yes 是 |
Excludes typedefs, type aliases, and const qualifier on value parameters. Includes ellipses. 排除值参数的typedef、类型别名及const限定符。包含省略号。 |
| Return type 返回类型 |
No 否 |
注意:函数返回类型不用于区分重载函数,稍后将详细说明。
对于进阶读者
对于成员函数,还会考虑额外的函数级限定符:
Function-level qualifier
函数级限定符Used for overloading
是否用于区分重载const or volatile
const 或 volatileYes
是Ref-qualifiers
引用限定符Yes
是例如:const成员函数可与形参完全相同的非const成员函数区分(即使它们共享相同形参集)。
相关内容
第20.5课——省略号(及避免使用的原因)将讲解省略号。
基于形参数量的重载
只要每个重载函数的形参数量不同,即可实现区分。例如:
int add(int x, int y)
{
return x + y;
}
int add(int x, int y, int z)
{
return x + y + z;
}
编译器可轻松识别:带两个整数形参的调用应指向 add(int, int),带三个整数形参的调用应指向 add(int, int, int)。
基于形参类型的重载
只要每个重载函数的形参类型列表不同,即可实现区分。例如以下所有重载均可区分:
int add(int x, int y); // integer version
double add(double x, double y); // floating point version
double add(int x, double y); // mixed version
double add(double x, int y); // mixed version
由于类型别名(或typedef)并非独立类型,使用类型别名的重载函数无法与使用别名类型本身的重载区分。例如以下所有重载均无法区分(且会导致编译错误):
typedef int Height; // typedef
using Age = int; // type alias
void print(int value);
void print(Age value); // not differentiated from print(int)
void print(Height value); // not differentiated from print(int)
对于按值传递的形参,const限定符同样不予考虑。因此以下函数不被视为可区分:
void print(int);
void print(const int); // not differentiated from print(int)
对于进阶读者
虽然尚未介绍省略号参数,但省略号参数被视为特殊类型的参数:
void foo(int x, int y); void foo(int x, ...); // differentiated from foo(int, int)因此调用 foo(4, 5) 将匹配 foo(int, int),而非 foo(int, ...)。
函数返回类型不参与重载区分
区分重载函数时不考虑函数的返回类型。
假设你想编写一个返回随机数的函数,但需要一个返回整数的版本和一个返回双精度浮点数的版本。你可能会尝试这样写:
int getRandomValue();
double getRandomValue();
在 clang21 中,这会导致以下编译器错误:

这很合理。如果你是编译器,看到以下语句:
getRandomValue();
你会调用哪个重载函数?这并不明确。
顺带一提...
这是编译器的刻意设计,它确保函数调用的行为可独立于表达式其余部分确定,从而大幅简化复杂表达式的理解。换言之,我们始终能仅凭函数调用的参数确定调用的是哪个版本。若需通过返回值区分,则无法通过语法轻松识别调用的重载版本——还必须理解返回值的使用方式,这需要大量额外分析。
解决此问题的最佳方式是为函数赋予不同的名称:
int getRandomInt();
double getRandomDouble();
类型签名
函数的类型签名type signature(通常称为签名signature)定义为函数头部用于区分函数的组成部分。在C++中,这包括函数名、形参数量、形参类型以及函数级限定符。值得注意的是,它不包含返回类型。
名称修饰
顺带一提……
当编译器编译函数时,它会执行名称修饰name mangling,即根据各种标准(如形参的数量和类型)对函数的编> 译后名称进行更改("修饰"),以便链接器能够使用唯一的名称进行工作。例如,原型为 int fcn() 的函数可能编译为修饰名 __fcn_v,而 int fcn(int) 则可能编译为修饰名 __fcn_i。因此在源代码中,这两个重载函数共享 fcn() 名称,但在编译后的代码中,修饰名是唯一的(__fcn_v 与 __fcn_i)。
名称修饰方式没有统一标准,因此不同编译器生成的修饰名称各不相同。

浙公网安备 33010602011771号