用C ++覆盖Base的重载函数

时间:2009-05-20 14:24:08

标签: c++ inheritance polymorphism override

  

可能重复:
  C++ overload resolution

我遇到了一个问题,在我的类重写了它的基类函数之后,所有函数的重载版本都被隐藏了。这是设计还是我做错了什么?

实施例

class foo
{
  public:
    foo(void);
    ~foo(void);
    virtual void a(int);
    virtual void a(double);
};

class bar : public foo 
{
  public:
    bar(void);
    ~bar(void);
    void a(int);
};

以下将给出编译错误,说明条中没有(双)函数。

main() 
{
  double i = 0.0;
  bar b;
  b.a(i);
}

3 个答案:

答案 0 :(得分:67)

在课程栏中,添加

using foo::a;

这是C ++中常见的“问题”。一旦在类范围中找到名称匹配,它就不会进一步查看继承树的重载。通过指定'using'声明,您可以将'f'中的'a'的所有重载带入'bar'的范围。然后重载正常工作。

请记住,如果现有代码使用'foo'类,其含义可能会被其他重载更改。或者额外的重载可能会引入歧义,并且代码将无法编译。 James Hopkin的回答指出了这一点。

答案 1 :(得分:20)

这就是语言运作的方式。在使用关键字之前,如果您覆盖了一个重载函数,则必须将它们全部重载:

class bar : public foo 
{
  public:
    bar(void);
    ~bar(void);
    a(int);
    a(double d) { foo::a(d); }  // add this
}

这让很多人感到恼火,语言委员会添加了使用功能,但是一些旧习惯很难过;和habitués†有一个很好的争论。

正如James Hopkins指出的那样,通过添加使用,程序员表达了这样的意图:派生类将在没有警告的情况下将foo :: a()的任何未来覆盖添加到其列表中可接受的签名。

以下是他描述的一个例子:

#include <iostream>
class Base {
public:
  virtual void f(double){ std::cout << "Base::Double!" << std::endl; }
  // virtual void f(int) { std::cout << "Base::Int!" << std::endl; } // (1)
  virtual ~Base() {}
};

class Derived : public Base {
public:
  // using Base::f; // (2)
  void f(double) { std::cout << "Derived::Double!" << std::endl; }
};

int main(int, char **) {
  Derived d;
  d.f(21);
  return 0;
}

输出将是“Derived :: Double!”因为编译器会将整数参数提升为double。 g ++ 4.0.1 -Wall不会警告此促销活动已经发生。

取消注释(1)以模拟对Base添加方法Base :: f(int)的未来更改。即使使用-Wall,代码也会在没有任何警告的情况下编译,并且“Derived :: Double!”仍然是输出。

现在取消注释(2)模拟Derived程序员决定包含所有Base :: f签名。代码编译(没有警告),但输出现在是“Base :: Int!”。

-

†我想不出一个英文单词“有习惯的人”和“上瘾”太强了。

答案 2 :(得分:11)

这是设计的。过载分辨率仅限于单个范围。当附加函数被添加到基类或命名空间范围时,它可以防止一些令人讨厌的有效代码更改意义。