一、函数重载的概念
两个以上的函数具有相同的函数名,但形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数重载(overloading)。
如果没有重载,对不同类型的数据进行相同操作时,必须给每个函数起不同的名字,使用起来很不方便。
// 没有重载时,需要不同的函数名
int iAdd(int x, int y);
float fAdd(float x, float y);
int main()
{
cout << iAdd(1, 2) << endl;
cout << fAdd(1.1f, 2.2f) << endl;
return 0;
}Code language: JavaScript (javascript)
使用函数重载后,可以用同一个函数名处理不同类型的数据:
int Add(int x, int y);
float Add(float x, float y);
float Add(float x, float y, float z);
float Add(float x, int y, float z);
二、函数重载的规则
- 函数名必须相同。
- 形参的个数或类型必须不同(两者至少满足其一)。
- 返回值类型可以相同也可以不同,但仅返回值类型不同不足以构成重载。
编译器根据实参的个数和类型进行最佳匹配,选择调用对应的函数。如果匹配失败或存在二义性,编译报错。
三、判断是否为重载函数的标准
| 条件 | 说明 |
|---|---|
| 函数名相同 | 必须一致 |
| 参数个数不同 或 参数类型不同 | 至少满足其一 |
| 返回值类型 | 与重载无关,不能仅靠返回值类型区分 |
以下情况不是重载,会被视为重复定义:
int func(int x);
double func(int x); // 错误:仅返回值不同,参数列表相同
int func(int x, int y = 10);
int func(int x); // 错误:参数列表本质相同(第二个有默认值)Code language: JavaScript (javascript)
四、代码示例
以下代码演示了函数重载的各种形式:
#include <iostream>
#include <string>
using namespace std;
// 重载1:两个整数相加
int Add(int x, int y)
{
cout << "调用 Add(int, int): ";
return x + y;
}
// 重载2:两个浮点数相加
float Add(float x, float y)
{
cout << "调用 Add(float, float): ";
return x + y;
}
// 重载3:三个浮点数相加
float Add(float x, float y, float z)
{
cout << "调用 Add(float, float, float): ";
return x + y + z;
}
// 重载4:混合类型(float, int, float)
float Add(float x, int y, float z)
{
cout << "调用 Add(float, int, float): ";
return x + y + z;
}
// 重载5:三个整数相加
int Add(int x, int y, int z)
{
cout << "调用 Add(int, int, int): ";
return x + y + z;
}
// 以下不是重载,编译会报错(与重载1参数列表相同,仅返回值不同)
/*
float dAdd(int x, int y)
{
return x + y;
}
*/
int main()
{
cout << Add(1, 2) << endl; // 匹配 Add(int, int)
cout << Add(1.1f, 2.2f) << endl; // 匹配 Add(float, float)
cout << Add(1.1f, 2.2f, 3.3f) << endl; // 匹配 Add(float, float, float)
cout << Add(1.1f, 2, 3.3f) << endl; // 匹配 Add(float, int, float)
cout << Add(1, 2, 3) << endl; // 匹配 Add(int, int, int)
return 0;
}Code language: PHP (php)
五、默认形参值与函数重载的二义性
当带默认形参值的函数参与重载时,需要特别注意防止调用时产生二义性。
void fun(int length, int width = 2, int height = 33);
void fun(int length);Code language: JavaScript (javascript)
当以 fun(1); 形式调用时,编译器无法确定应该调用哪个函数:
- 匹配
fun(int length, int width = 2, int height = 33)→ 实参 1 传给 length,width 和 height 使用默认值 - 匹配
fun(int length)→ 实参 1 传给 length
两个匹配都合法,编译器无法确定最佳匹配,产生二义性错误。
六、练习:求两数和的平方(重载函数)
题目:编写两个名为 sumOfSquare 的重载函数,分别求出两整数以及两实数的平方和。
#include <iostream>
using namespace std;
// 重载1:两个整数
int sumOfSquare(int x, int y)
{
return x * x + y * y;
}
// 重载2:两个浮点数
float sumOfSquare(float x, float y)
{
return x * x + y * y;
}
int main()
{
cout << "整数 1 和 2 的平方和 = " << sumOfSquare(1, 2) << endl;
cout << "浮点数 1.1 和 2.2 的平方和 = " << sumOfSquare(1.1f, 2.2f) << endl;
return 0;
}Code language: PHP (php)
七、注意事项
- 函数重载与返回值类型无关,仅返回值不同不能构成重载。
- 形参名不同不能构成重载:
int func(int a);和int func(int b);是同一个函数。 typedef定义的类型别名与原类型视为同一类型,不能构成重载:
typedef int INTEGER;
int func(int x);
int func(INTEGER x); // 错误:INTEGER 就是 intCode language: JavaScript (javascript)
- 当实参存在隐式类型转换时,编译器会选择”最佳匹配”。如果多个重载函数都能匹配且没有一个明显更优,则产生二义性。
- 默认形参值与重载结合时容易产生二义性,设计时应避免。
- 引用和值传递可以构成重载,但调用时可能产生二义性:
void foo(int x);
void foo(int &x);
int a = 5;
foo(a); // 二义性:两个都能匹配Code language: JavaScript (javascript)
八、常见错误
1. 仅靠返回值类型不同
int func(int x);
double func(int x); // 错误:不是重载,重复定义Code language: JavaScript (javascript)
2. 形参名不同
int func(int a, int b);
int func(int x, int y); // 错误:参数类型相同,是同一个函数Code language: JavaScript (javascript)
3. 默认形参与重载产生二义性
void bar(int a, int b = 10);
void bar(int a);
bar(5); // 二义性Code language: JavaScript (javascript)
4. typedef 类型不能构成重载
typedef double REAL;
double func(double x);
double func(REAL x); // 错误:REAL 就是 doubleCode language: JavaScript (javascript)