📄 一句话概括
重载 = 同一个函数名、多套参数表。调用时编译器看实参的个数和类型,决定进哪一个版本。区分只靠参数表——返回值不同、参数名不同都不算重载。
📝 本节和前面几节的关系
6.4 讲的"同名遮蔽"是不同作用域里的同名;这一节反过来——在同一个作用域里故意同名。其实你早就用过重载了:cout << 能打印整数、小数、字符、字符串,因为 << 运算符本身被重载过(第二章就在享受这个便利)。用到的旧知识:函数头三部件(6.1.1)、类型转换楼梯(3.3.2)。
一、写法与效果
void print(int n) { cout << "整数:" << n << endl; }
void print(double d) { cout << "小数:" << d << endl; }
void print(char c, int n) { for (int i = 0; i < n; i++) cout << c; cout << endl; }
print(5); // → 进 print(int)
print(3.14); // → 进 print(double)
print('*', 6); // → 进 print(char, int)
名字完全一样,做的事按参数自动分派——这就是"同名多面"。好处:调用方不用记一堆名字(不用 printInt/printDouble/printChars),语义一致的操作用一个名字就够。
二、靠什么区分(重载的判据)
| 能区分(合法重载) | 不能区分(编译错误) |
|---|---|
参数个数不同:f(int) / f(int,int) |
只有返回类型不同:int f() / double f() |
参数类型不同:f(int) / f(double) |
只有参数名不同:f(int a) / f(int b) |
参数顺序不同:f(int,double) / f(double,int) |
— |
一句话:参数表就是唯一的身份证。
三、编译器怎么选(三步)
以 print(3.14) 为例:
- 先找完全匹配——有
print(double)吗?有 → 就是它 - 没有就找能隐式转换的——比如没有
print(int)时传5,int → double能转(3.3.2 的楼梯,只上不下),就用print(double) - 多个都能转 → 报错——这叫二义性(ambiguous),编译器拒绝替你猜
⚠️ 二义性的经典现场:
void f(int x);
void f(double x);
f('A'); // char 既能转 int、也能转 double → 报错 ambiguous
四、实例 06:定义重载函数
#include <iostream>
using namespace std;
void show(int n) { // ① 一个整数
cout << "整数:" << n << endl;
}
void show(double d) { // ② 一个小数
cout << "小数:" << d << endl;
}
void show(char c, int n) { // ③ 一个字符 + 一个次数
cout << "字符串:";
for (int i = 0; i < n; i++) cout << c;
cout << endl;
}
int main() {
show(42); // ①
show(3.14); // ②
show('*', 5); // ③
show(7.0f); // float → 隐式提升成 double,进 ②
return 0;
}
看到什么算成功:
整数:42
小数:3.14
字符串:*****
小数:7
注意最后一行 show(7.0f):传的是 float,但没有 show(float) 这个版本——编译器把它隐式提升成 double(3.3.2 的"楼梯只上不下"),进了 ② 号门。这说明重载匹配允许隐式转换,同时也说明转换多了就有歧义风险。
30 秒实验:加一个 void show(float f) 版本,再调 show(7.0f)——现在它会精确匹配新版本;而 show(42) 反而要让编译器在 "int→float" 和 "int→double" 之间做选择,有些编译器会在这里报歧义。体会:重载版本越多,越要小心歧义。
五、常见误区
- "返回值不同也能重载"——不能,而且会报"重复定义"。只有参数表能区分。
- "只写声明就算重载"——每个重载版本都必须有完整的定义。
- "重载是把原来的覆盖了"——不是覆盖,是并存。编译器按实参挑一个用,其余的都还在。
- "重载和默认参数可以随便混"——容易出歧义:
f(int a, int b = 0)与f(int a)同时存在时,f(5)两边都能接 → 报错。两者尽量择一使用。 - "重载是运行时判断的"——不是,它完全发生在编译期,运行时零额外开销。这一点和后面章节的"虚函数(多态)"完全不同。
自测三问(点开对答案)
1. 重载靠什么区分?——参数表:参数的个数、类型、顺序;返回值不同不算。 2. 什么是二义性?——多个重载版本都能通过隐式转换接受同一组实参,编译器无法选择。 3. 重载是编译期还是运行期决定?——编译期,运行时没有额外开销。- ☐ 6.6 内联函数(下一节)
相关笔记
- 变量作用域 —— 跨作用域同名 vs 同作用域同名
- 表达式中的类型转换 —— 重载匹配里的隐式转换
- C++语言中的流 ——
<<就是重载的受益者 - 🔷 C++基础 · 索引 —— 全课路线图