函数重载决议与二义性解析
在发生函数调用时,编译器会根据实参的数量、类型和顺序,从候选的重载函数中选出最合适的一项。对参数类型不完全匹配的场景,C++ 按照以下优先级逐级搜索:
-
精确匹配(Exact Match)
-
类型提升(Promotion)
- 整型提升:
bool 、char 、short → int ;char16_t /char32_t /wchar_t → int /long /long long
- 浮点提升:
float → double
-
标准转换(Conversion)
- 整型转换:
short → long 、int → short 、long → char …
- 浮点转换:
double → float
- 整浮转换:
int ↔ double 、short → float 、float → int …
- 指针转换:如
int* → void*
- 用户自定义转换 / 构造函数(此处略)
一旦在某个级别找到唯一匹配,即停止搜索;若在该级别有多于一个可行匹配,则报二义性错误,不会继续往下级别搜索。
一、单参数示例
#include <iostream>
using namespace std;
void func(char) { cout << "#1"; } // 精确匹配 char
void func(int) { cout << "#2"; } // 精确匹配 int
void func(long) { cout << "#3"; } // 精确匹配 long
void func(double) { cout << "#4"; } // 精确匹配 double
int main(){
short s = 99;
float f = 84.6f;
func('a'); // #1 :精确匹配 char
func(s); // #2 :short → int(整型提升)
func(49); // #2 :字面量 49 类型为 int
func(f); // #4 :float → double(浮点提升)
}
关键点
short 、float 都先做“提升”再匹配。
- 只有当没有更高优先级的匹配时,才会进入“转换”阶段。
二、缺少精确或提升匹配时的二义性
去掉 func(int) 后的例子:
void func(char);
void func(long);
void func(double);
short s = 99;
func(s); // 编译错误:short→long(转换) 与 short→char(转换) 同级,二义性
func(49); // 同上:49(int) 可转换到 long 或 double,二义性
- 此时
s 和 49 均无法精确或提升匹配(缺少 int 重载),进入标准转换阶段。
-
对 short :
short→long (整型转换)
short→char (整型转换)
short→double (整浮转换)
三者同处一个级别,编译器无法区分,报错。
三、多参数重载的二义性判定
当函数有多个参数时,C++ 规定:
若且仅若 函数 A 对“每个实参”的匹配都不劣于 函数 B,且至少对一个实参的匹配优于 B,则 A 胜出。
示例
// 候选重载
void func(int, int); // ①
void func(char, int, float); // ②
void func(char, long, double); // ③
short n = 99;
char c = '@';
double d = 99.5;
-
func(c, n, 99)
- ①:参数个数不符,剔除。
-
对比② vs. ③:
- 首参
char 精确匹配(平手)
- 次参
short→int (提升) vs. short→long (转换) → ② 优
- 三参 int→float vs. int→double(都属于标准转换) → ②③ 平手
- ② 在每个参数上都不劣于 ③,且在次参上更优,选②。
-
func(c, n, d)
- ① 同上剔除。
-
对比② vs. ③:
- 首参 平手
- 次参 ② 优(提升 vs. 转换)
- 三参
float→double (提升) vs. double 精确 → ③ 优
- ②、③ 各有一胜,无法分出优劣,二义性,报错。
四、避免重载二义性的建议
-
减少相近签名
- 不要仅靠标准转换来区分;必要时可显式添加针对性的重载。
-
使用模板或不同函数名
- 对一组类型通用的操作,优先考虑函数模板,以消除歧义。
-
谨慎设计可选参数
小结
- 匹配级别:精确 > 提升 > 转换。
- 唯一性:每个级别只要找到唯一最优,即可绑定;否则报二义性错误。
- 多参数时,按照“不劣于”+“一优于”原则判定最优解。
- 合理规划重载与模板,可有效避免歧义,提升代码健壮性与可读性。
|