C++ 函数重载实战指南:同名不同签名的多态艺术
C++ 函数重载完全指南
深度解析 C++ 函数重载机制:同名函数通过参数列表差异(类型、个数、顺序)共存,附实战示例与重载决议规则。
C++ 允许同名函数共存,前提是参数列表不同(类型、个数、顺序任一不同)。这些变体称为重载函数。
例如:
// 同名,不同参数
int Test() { }
int Test(int a) { }
float Test(double a) { }
int Test(int a, double b) { }
上述四个声明构成合法重载集。返回类型不参与重载决议;仅看参数列表。例如:
// 编译错误:签名相同
int Test(int a) { }
double Test(int b) { }
两者参数列表完全一致,编译器报重复定义错误。
示例 1:不同参数类型重载
// 分别计算 int 和 float 绝对值
#include <iostream>
using namespace std;
// float 版本
float Absolute(float var) {
return (var < 0.0f) ? -var : var;
}
// int 版本
int Absolute(int var) {
return (var < 0) ? -var : var;
}
int main() {
cout << "Absolute value of -5 = " << Absolute(-5) << endl;
cout << "Absolute value of 5.5 = " << Absolute(5.5f) << endl;
return 0;
}
输出
Absolute value of -5 = 5 Absolute value of 5.5 = 5.5
编译器根据实参类型(int vs float)选择对应重载。
示例 2:不同参数个数重载
#include <iostream>
using namespace std;
// 双参数版本
void Display(int var1, double var2) {
cout << "Integer: " << var1;
cout << " & Double: " << var2 << endl;
}
// 单 double 参数
void Display(double var) {
cout << "Double: " << var << endl;
}
// 单 int 参数
void Display(int var) {
cout << "Integer: " << var << endl;
}
int main() {
int a = 5;
double b = 5.5;
Display(a); // 调用 int 版本
Display(b); // 调用 double 版本
Display(a, b); // 调用双参数版本
return 0;
}
输出
Integer: 5 Double: 5.5 Integer: 5 & Double: 5.5
调用根据实参个数与类型精准解析到对应重载。
重载决议规则核心(简化版)
- 精确匹配:实参类型与形参完全一致(含 cv 限定、引用)
- 提升/转换匹配:整型提升(
char→int)、标准转换(int→double)、用户定义转换 - 椭圆参数(
...)优先级最低 - 若存在多个同样优秀的候选 → 歧义错误
歧义示例
void Foo(int);
void Foo(double);
Foo(3.14); // OK:精确匹配 double
Foo(42); // OK:精确匹配 int
Foo('a'); // 错误:char 可提升为 int,也可转换为 double,同级歧义
重载 vs 模板 vs 缺省参数:选型指南
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 同一语义、少数固定参数组合 | 函数重载 | 语义清晰,编译期决议零开销 | 同一算法、任意类型参数 | 函数模板 | 代码复用最大化,类型安全 |
| 同一函数、部分参数有合理默认值 | 缺省参数 | 减少重载数量,保持单一定义 |
| 需根据运行时类型分发 | 虚函数/多态 | 动态绑定,重载是静态绑定 |
sqrt() 大量重载(int、float、double、long double、complex 等),为开发者提供极大灵活性。避坑指南
- 不要仅靠返回类型重载:编译错误
- 避免隐式转换导致歧义:如
void F(int)与void F(double)共存时调用F(3.14f)(float→double 标准转换 vs float→int 提升+转换)可能产生意外选择 - 默认参数与重载组合:可能产生歧义,如
void F(int, int=0)与void F(int, int, int)调用F(1,2)歧义 - 作用域遮蔽:派生类同名函数会隐藏基类所有重载,需
using Base::F;引入
C语言