为什么指定默认参数时函数重载不起作用?

Why doesn't function overloading work when default parameters are specified?

提问人:Kim_Yeon_Shin_01 提问时间:4/2/2023 最后编辑:Remy LebeauKim_Yeon_Shin_01 更新时间:4/3/2023 访问量:126

问:

如果未指定默认参数,则函数重载起作用。

但是,为什么指定默认参数时函数重载不起作用?

该程序采用两个整数并比较它们以找到两者中较大的一个。

然后,它将最大值与之前获得的较大整数进行比较,并输出较小的值。

这是我写的代码

#include <iostream>
using namespace std;

int big(int a, int b);
int big(int a, int b, int max = 100);

int big(int a, int b) {
    if (a > b)
        if (a > 100)
        {
            return 100; 
        }
        else {
            return a; 
        }
    else {
        if (b > 100) {
            return 100; 
        }
        else
        {
            return b; 
        }
    }
}

int big(int a, int b, int max) {
    if (a > b) {
        if (a < max) {
            return a; 
        }
        else
        {
            return max; 
        }
    }
    else {
        if (b < max) {
            return b; 
        }
        else {
            return max; 
        }

    }
}
  
int main() {
    int x = big(3, 5); 
    int y = big(300, 60); 
    int z = big(30, 60, 50); 
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

当我调试我编写的代码时,它说

E0308编译错误:重载函数的多个实例与参数列表匹配

我了解到,当函数参数不同时,函数重载可以起作用。

在我的代码中,函数名称相同,但函数参数不同:

(int x, int y) and (int x, int y, int max)

但它不起作用。

总之,为什么指定默认参数时函数重载不起作用?

我使用的IDE:

Microsoft Visual Studio Community 2022(64 位)- 当前版本 版本。17.5.1

这是期望的结果:

  1. 变量并具有第一个函数的返回值xybig(int x, int y)
  2. 变量具有第二个函数的返回值zbig(int x, int y, int max = 100)

这个问题是相关的,但我不明白解决方案是如何实现的。

c++ default-parameters 函数-templates-重载

评论

1赞 Vlad from Moscow 4/2/2023
如果只提供两个参数,如何确定要调用哪个函数?
2赞 selbie 4/2/2023
函数重载被高估,使用默认参数可能很危险。这个例子是我不允许函数重载和不鼓励我的团队使用默认参数的几个原因之一。没有人因为函数的命名不同而受到伤害。如果您需要两个函数,请显式命名它们:和或类似的东西。如果需要默认参数,请创建一个单独命名的存根函数,该函数采用较少的参数,并使用硬编码的参数值调用另一个函数。bigbigbigWithMax
1赞 molbdnilo 4/2/2023
如果不能仅使用两个参数调用它,为什么还要给三参数重载一个默认参数?
0赞 Peter 4/2/2023
想象一下你这样做.有两个同样可行的选项 - 或,并且该标准没有给出要求偏爱一种形式的标准(根据一些程序员的说法,无论标准做出哪种选择,它都是“错误的”,并且 SO 会收到问题“为什么不选择另一种?相反,该标准称其为可诊断的错误,需要程序员解决问题。解决方法:消除歧义 - 要么完全消除双参数形式,要么消除默认值。int biggest = big(1,2);int big(int a, int a)int big(int a, int b, int max = 100)

答:

1赞 selbie 4/2/2023 #1

实际上,这两个函数的名称相同

int big(int a, int b) {}

int big(int a, int b, int max=100) {}

然后当你调用....big(3,5)

你到底希望得到哪个版本的称呼?第一个实现显式采用两个参数,还是第二个实现可以采用两个或三个参数?big

编译器通过出错并告诉您它是模棱两可的来帮你一个忙。

正如我在评论中指出的那样,函数重载被高估了。只需显式命名函数,这样调用哪个实现就没有歧义了。

此外,您的整个实现可以简化为一个函数和两行代码

int big(int a, int b, int max=100) {
    int result = (a > b) ? a : b;
    return (result > max) ? max : result;
}

如果您将 max 的默认参数保留为没有重载的单个函数,对我来说似乎是无害的。

0赞 JuliusDC 4/2/2023 #2

这部分是模棱两可的,因为第二个函数声明有一个默认参数:

int big(int a, int b);
int big(int a, int b, int max = 100);

因此,当您调用 big(20,30) 时,可以使用两个版本的 big()。所以会有 2 名候选人。

使用函数的第二个版本使其在不重载的情况下工作就足够了。 像这样的东西:

#include <iostream>
using namespace std;

// declare
int big(int a, int b, int max = 100);

// define
int big(int a, int b, int max) {
    if (a > b) {
        if (a < max) {
            return a;
        }
        else
        {
            return max;
        }
    }
    else {
        if (b < max) {
            return b;
        }
        else {
            return max;
        }

    }
}

int main() {
    int x = big(3, 5);
    int y = big(300, 60);
    int z = big(30, 60, 50);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

如果您仍想定义 2 个函数。我建议你删除默认参数。

#include <iostream>
using namespace std;

int big(int a, int b);
int big(int a, int b, int max);

int big(int a, int b) {
    if (a > b)
        if (a > 100)
        {
            return 100;
        }
        else {
            return a;
        }
    else {
        if (b > 100) {
            return 100;
        }
        else
        {
            return b;
        }
    }
}

int big(int a, int b, int max) {
    if (a > b) {
        if (a < max) {
            return a;
        }
        else
        {
            return max;
        }
    }
    else {
        if (b < max) {
            return b;
        }
        else {
            return max;
        }

    }
}

int main() {
    int x = big(3, 5);
    int y = big(300, 60);
    int z = big(30, 60, 50);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

额外说明:关于声明和定义函数。由于您在同一个源文件之前定义了函数 int,因此您可能不需要声明然后定义。因此,您可以跳过声明它。如果将实现移动到另一个源文件或 main() 之后,则声明它。 更多信息: 链接