函数重载

一、函数重载的概念

两个以上的函数具有相同的函数名,但形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数重载(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);

二、函数重载的规则

  1. 函数名必须相同。
  2. 形参的个数或类型必须不同(两者至少满足其一)。
  3. 返回值类型可以相同也可以不同,但仅返回值类型不同不足以构成重载。

编译器根据实参的个数和类型进行最佳匹配,选择调用对应的函数。如果匹配失败或存在二义性,编译报错。

三、判断是否为重载函数的标准

条件说明
函数名相同必须一致
参数个数不同 或 参数类型不同至少满足其一
返回值类型与重载无关,不能仅靠返回值类型区分

以下情况不是重载,会被视为重复定义:

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)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注