オーバーロードされた仮想関数を再宣言する必要があるのはなぜですか?

Nov 26 2020

2つのオーバーロードされた関数f(void)とを含む基本クラスがありf(int)ます。クラスDerivedf(int)を呼び出すことによって実装しf(void)ます。Derived2実装f(void)のみ。

コンパイラーはDerived::f(int)呼び出したいので実装を拒否しますf(int)が、呼び出したいので引数を指定しませんでしたf(void)。コンパイラがそれを拒否するのはなぜですか?行を追加virtual int f(void) = 0;すると問題が解決するのはなぜですか?

class Base
{
public:
  explicit Base(void) {}
  virtual ~Base(void) {}

  virtual int f(void) = 0;
  virtual int f(int i) = 0;
};

class Derived : public Base
{
public:
  // provide implementation for f(int) which uses f(void). Does not compile.
  virtual int f(int i) {puts("Derived::f(int)"); return f();}
  // code only compiles by adding the following line.
  virtual int f(void) = 0;
};

class Derived2 : public Derived
{
public:
  // overwrite only f(void). f(int) is implemented by Derived.
  virtual int f(void) {puts("Derived2::f(void)"); return 4;}
};

int main(void)
{
  Base * p = new Derived2();
  int i0 = p->f();  // outputs Derived2::f(void) and returns 4
  int i1 = p->f(1); // outputs "Derived::f(int) Derived2::f(void)" and return 4
  delete p;
  return 0;
}

回答

5 songyuanyao Nov 26 2020 at 08:18

Derived::fBase::fsを非表示にします。与えられたreturn f();のボディにDerived::f(int)、名前がfの範囲で発見されDerived、その後、ルックアップ名停止を。の名前Baseが見つからず、過負荷の解決に参加します。

名前ルックアップは、以下で説明するようにスコープを調べ、任意の種類の宣言が少なくとも1つ見つかるまで調べます。その時点でルックアップは停止し、それ以上のスコープは調べられません。

のスコープにusing Base::f;名前を導入するために追加できます。BaseDerived

class Derived : public Base
{
public:
  using Base::f;

  // provide implementation for f(int) which uses f(void).
  virtual int f(int i) {puts("Derived::f(int)"); return f();}
};