函数重载允许在同一作用域内声明多个同名函数,只要其参数列表在类型或个数上可区分。编译器根据实参类型与个数选择最匹配的版本(重载决议);仅返回值类型不同不能构成重载。本节在函数基础之上说明匹配规则、与 const 的关系及避免歧义的写法。
类型不同:基本示例
#include <iostream>
int max(int a, int b) {
return (a > b) ? a : b;
}
double max(double a, double b) {
return (a > b) ? a : b;
}
int main() {
std::cout << max(3, 7) << " " << max(2.5, 1.1) << std::endl;
return 0;
}max(3, 7) 两个实参均为 int,选择整型版本;max(2.5, 1.1) 为 double,选择浮点版本。若写 max(3, 2.5),通常经隐式转换统一为浮点版本,具体以标准转换序为准。
参数个数不同
#include <iostream>
#include <string>
void print(int x) {
std::cout << x << std::endl;
}
void print(int x, int y) {
std::cout << x << ", " << y << std::endl;
}
void print(const std::string& s) {
std::cout << s << std::endl;
}调用 print(1)、print(1, 2)、print("hi") 分别匹配不同重载。字符串字面量可构造 std::string 匹配第三版。
决议规则(直观)
| 情况 | 结果 |
|---|---|
| 存在唯一最佳匹配 | 调用该重载 |
| 多个重载同样合适 | 编译错误(歧义) |
| 需要多级不相关转换才能匹配 | 常报错或匹配失败 |
| 仅返回类型不同 | 非法重载 |
设计接口时,不要让一次常见调用能同时套上两个重载、且编译器分不出谁更匹配。例如同时提供 void f(int) 与 void f(long),传入 short 时两边都要转换,可能直接报歧义,或选到你没预期的那一个。
const 与重载
非成员函数中,void g(int) 与 void g(const int) 对按值传递不构成有效重载(形参均为 int)。指针与引用类型的 const 位置不同会形成不同签名,例如 void h(int*) 与 void h(const int*)。成员函数可因 const 限定而重载(在类中),见类与对象。
与默认参数的关系
不要使“带默认参数的一个函数”与“另一个参数更少的重载”在相同调用形式下均可匹配,例如:
void f(int x);
void f(int x, int y = 0); // 调用 f(1) 时歧义默认参数的细节见默认参数一节;重载与默认参数应一并设计,避免重复表达同一调用路径。
何时不用重载
若各版本语义差异很大(例如 open 与 open_config),不同函数名往往更易读。重载适合“同一操作、不同类型或参数个数”的紧密族系,如 operator<< 对流与多种类型的输出。
本节说明了函数重载的动机与匹配方式。下一节介绍默认参数:为形参指定默认值以简化调用。