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

Gre*_*reg 47 c++ polymorphism inheritance overriding

可能重复:
C++重载决议

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

防爆.

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);
};
Run Code Online (Sandbox Code Playgroud)

然后,下面会给出一个编译错误,说明条中没有(双)函数.

main() 
{
  double i = 0.0;
  bar b;
  b.a(i);
}
Run Code Online (Sandbox Code Playgroud)

Fre*_*son 72

在课堂栏中,添加

using foo::a;
Run Code Online (Sandbox Code Playgroud)

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

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

  • 值得记住的是James Hopkin关于将附加函数添加到基类时有效代码更改含义的观点. (3认同)

Tho*_*day 21

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

class bar : public foo 
{
  public:
    bar(void);
    ~bar(void);
    a(int);
    a(double d) { foo::a(d); }  // add this
}
Run Code Online (Sandbox Code Playgroud)

这使得语言委员会增加了使用功能的人很烦,但是一些旧的习惯很难; 和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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

-

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


Jam*_*kin 12

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