函数重载 - 两个函数仅由默认参数不同

时间:2012-03-30 13:06:43

标签: c++ overloading

class A{
    public:
        void foo(int x)
        {
            cout << "foo with one\n";
        }

        void foo(int x, int y=10)
        {
            cout << "foo with two\n";
        }
};

int main()
{
    A a;
    a.foo(1);   //error?
}

那么,为什么我不能用带有默认参数的函数重载void foo(int)

7 个答案:

答案 0 :(得分:5)

不能基于传递的参数的来重载函数,因此也不允许基于default参数的值进行重载。

您只能在以下基础上重载功能:

  • 参数类型
  • 参数数量
  • 参数序列&amp;
  • constvolatile等限定符。

当然,编译器是否接受过载取决于以下事实:
如果编译器明确地解析了对函数的调用。

在你的情况下,编译器无法解决歧义,例如:如果你简单地调用函数,编译器就不会知道调用哪个重载函数:

 foo(100);

编译器无法做出决定,因而无法做出错误。

答案 1 :(得分:3)

不,你不能,用一个参数调用函数时会有歧义。

如果你需要这样做,那就是代码味道。

答案 2 :(得分:2)

为什么不呢?

class A{
public:

    void foo(int x=10, int y=10)
    {
        cout << "foo with two\n";
    }

};

答案 3 :(得分:2)

推荐这个,但你 CAN 定义了这种模棱两可的方法,并通过不同的接口使用它们。  (以下至少使用gcc 4.8.0使用-std = c ++ 11。)

考虑两个接口:

class IInterface1
{
public:
   virtual void funky(int i) = 0;
   virtual void funky(int i, int j) = 0;
};

class IInterface2
{
public:
   virtual void funky(int i, int j = 0) = 0;
};

IInterface1对于不同的参数重载了两次funky方法,即相同的方法名称,但是一个采用单个int,而另一个采用两个整数。请注意,在接口实现中,funky方法需要具有两个实现(一个用于一个参数,另一个用于两个参数)。

IInterface2具有单funky方法,在调用时可以使用一个或两个整数。如果没有明确提供,则第二个int是默认的。请注意,在接口实现中,funky方法只需要一个实现(无论是否在调用期间提供了一个或两个参数,它总是需要两个参数)。

实现两个接口的类:

class Foo : public IInterface1, public IInterface2
{
public:
   void funky(int i) override
      { printf("  funky(int i) -> funky(%d)\n", i); }
   void funky(int i, int j = 0) override
      { printf("  funky(int i, int j = 0) -> funky(%d, %d)\n", i, j); }
   void funky(int i, int j = 0, int k = 0)
      { printf("  funky(int i, int j = 0, int k = 0) -> funky(%d, %d, %d)\n", i, j, k); }
};

为了说明,Foo还添加了第三个重载版本的funky方法,一个带有三个参数(一个是强制的,两个是可选的)。

现在可以使用

Foo,如下图所示。 Foomaster的实例可以直接使用,也可以由不同的客户端访问master对象的不同接口。

Foo master;
IInterface1& client1 = master;
IInterface2& client2 = master;

// AMBIGUOUS: master.funky(1); 
// AMBIGUOUS: master.funky(2,3);
puts("master.funky(4, 5, 6);");
master.funky(4, 5, 6);

puts("client1.funky(7);");
client1.funky(7);
puts("client1.funky(8, 9);");
client1.funky(8, 9);

puts("client2.funky(10);");
client2.funky(10);
puts("client2.funky(11, 12);");
client2.funky(11, 12);

这将产生以下输出:

master.funky(4, 5, 6);
  funky(int i, int j = 0, int k = 0) -> funky(4, 5, 6)
client1.funky(7);
  funky(int i) -> funky(7)
client1.funky(8, 9);
  funky(int i, int j = 0) -> funky(8, 9)
client2.funky(10);
  funky(int i, int j = 0) -> funky(10, 0)
client2.funky(11, 12);
  funky(int i, int j = 0) -> funky(11, 12)

总之,类可能有明显冲突的方法重载版本。调用方法时解决歧义必须(否则代码将无法编译)。

PS:再次,由于上述方法打破了KISS原则,我不会宽恕它。

答案 4 :(得分:1)

考虑一下 - 在编译时编译器必须决定选择什么。除非你提供这两个参数,否则我不能。所以编译器别无选择,只能举起手来说再试一次,代码不需要Mystic Meg。

答案 5 :(得分:0)

我想你不能。因为函数/运算符重载在编译时由编译器解决。因此,仅通过提供默认参数来重载函数将导致歧义和编译器错误。

答案 6 :(得分:0)

不会因为可选参数而产生歧义,而是仅当您具有相同的原型且具有相同的可选参数但名称不同的原型时才会发生。这就是我所发现的。

我实际上以为与您的示例相似的示例很幸运。.但是当我用相同的可选参数放置两个不同的原型名称时,它开始抱怨含糊不清

这在下面给出了歧义错误

void UpdateTextColor(HWND hwndControl, DWORD text_color, DWORD back_color, BOOL control_back_color);
void CreateColoredText(HWND hwndControl, DWORD text_color, DWORD back_color, BOOL control_back_color);

void UpdateTextColor(HWND hwndControl, DWORD text_color, DWORD back_color, BOOL control_back_color = FALSE)
{
   //...
}

void CreateColoredText(HWND hwndControl, DWORD text_color, DWORD back_color, BOOL control_back_color = FALSE)
{
   //...
}

但这不是,请注意,我仍在使用可选参数

void UpdateTextColor(HWND hwndControl, DWORD text_color, DWORD back_color);
void CreateColoredText(HWND hwndControl, DWORD text_color, DWORD back_color, BOOL control_back_color);

void UpdateTextColor(HWND hwndControl, DWORD text_color, DWORD back_color)
{
   //...
}

void CreateColoredText(HWND hwndControl, DWORD text_color, DWORD back_color, BOOL control_back_color = FALSE)
{
   //...
}

//My call is like this (note only 3 params used out of 4)

CreateColoredText(GetDlgItem(hDlg, BLAHBLAH), RGB(0, 0, 0), RGB(127, 127, 127));