¿Por qué necesito volver a declarar las funciones virtuales sobrecargadas?
Tengo una clase base con dos funciones sobrecargadas f(void)y f(int). La clase se Derivedimplementa f(int)llamando f(void). Derived2implementos f(void)solamente.
El compilador rechaza la implementación Derived::f(int)porque quiere llamar, f(int)pero no proporcioné argumentos porque quiero llamar f(void). ¿Por qué el compilador lo rechaza? ¿Por qué agregar la línea virtual int f(void) = 0;soluciona mi 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;
}
Respuestas
Derived::fesconde Base::fs. Dado return f();en el cuerpo de Derived::f(int), el nombre fse encuentra en el alcance de Derived, luego se detiene la búsqueda de nombres . Los nombres en Baseno se encontrarán y participarán en la resolución de sobrecarga.
La búsqueda de nombres examina los ámbitos como se describe a continuación, hasta que encuentra al menos una declaración de cualquier tipo, momento en el que la búsqueda se detiene y no se examinan más ámbitos.
Puede agregar using Base::f;para introducir el nombre de Baseen el alcance 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();}
};