Por que preciso redeclarar funções virtuais sobrecarregadas?

Nov 26 2020

Eu tenho uma classe base com duas funções sobrecarregadas f(void)e f(int). A classe Derivedimplementa f(int)chamando f(void). Derived2implementos f(void)apenas.

O compilador rejeita a implementação Derived::f(int)porque deseja chamar, f(int)mas não forneci argumentos porque desejo chamar f(void). Por que o compilador o rejeita? Por que adicionar a linha virtual int f(void) = 0;corrige meu problema?

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;
}

Respostas

5 songyuanyao Nov 26 2020 at 08:18

Derived::fesconde Base::fs. Dado return f();no corpo de Derived::f(int), o nome fé encontrado no escopo de Derivede a pesquisa de nome é interrompida. Os nomes em Basenão serão encontrados e participarão da resolução de sobrecarga.

A pesquisa de nomes examina os escopos conforme descrito abaixo, até encontrar pelo menos uma declaração de qualquer tipo, momento em que a pesquisa é interrompida e nenhum escopo adicional é examinado.

Você pode adicionar using Base::f;para introduzir o nome de Baseno escopo de Derived.

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();}
};