Por que preciso redeclarar funções virtuais sobrecarregadas?
Eu tenho uma classe base com duas funções sobrecarregadas f(void)
e f(int)
. A classe Derived
implementa f(int)
chamando f(void)
. Derived2
implementos 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
Derived::f
esconde Base::f
s. Dado return f();
no corpo de Derived::f(int)
, o nome f
é encontrado no escopo de Derived
e a pesquisa de nome é interrompida. Os nomes em Base
nã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 Base
no 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();}
};