2011-07-17 9 views
16

Tengo un problema con la herencia de C++.C++ Función virtual que se oculta

que tienen una jerarquía de clases:

class A { 
public: 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

class B : public A { 
public: 
    virtual void onFoo(int i) {} 
}; 

class C : public B { 
}; 


int main() { 
    C* c = new C(); 
    c->onFoo(); //Compile error - doesn't exist 
} 

Mi pregunta es: ¿por qué no esta compilar? Según entiendo, C debe heredar ambas funciones onFoo de A, y de hecho, compila si elimina la redefinición de onFoo en B, pero g ++ da un error de que C no tiene función onFoo().

Respuesta

33

El problema que está experimentando está relacionado con la forma en la búsqueda de nombres funciona en C++. En particular, al resolver un miembro, el compilador examinará el tipo estático del objeto al que se está accediendo al miembro. Si el identificador se encuentra en esa clase, la búsqueda se completa y (en el caso de las funciones miembro) se inicia la resolución de sobrecarga. Si no se encuentra el identificador, se arrastrará por la jerarquía, clase por clase, tratando de localizar el identificador un nivel a la vez.

En su caso particular, tiene c->onFoo(); y c es del tipo C. El compilador no ve ninguna declaración de onFoo en C, por lo que continúa hacia arriba en la jerarquía. Cuando el compilador comprueba B, ve que hay una declaración de void onFoo(int i) en ese nivel, por lo que detiene la búsqueda e intenta la resolución de sobrecarga. En este momento, la resolución de sobrecarga falla debido a la inconsistencia en los argumentos.

El hecho de que una declaración de void onFoo(int) está presente en B nivel tiene el efecto de ocultar el resto de las sobrecargas en cualquier clase de base, ya que dejará de búsqueda. Tenga en cuenta que este es un problema con la búsqueda no calificada, la función todavía está allí y es aplicable al objeto, pero no se encontrará mediante la búsqueda regular (todavía puede llamarlo como c->A::onFoo()).

A partir de cómo hacer frente a ocultar, la forma más sencilla es mediante el empleo de la declaración using para llevar las funciones en el alcance:

class B : A { 
public: 
    using A::onFoo; // All A::onFoo overloads are *considered* here 
    void onFoo(int); 
}; 

El efecto de la declaración using aquí es que cuando la clase B se busca, en la búsqueda del identificador onFoo, se indica al compilador que también considere todas las sobrecargas de onFoo en la clase base, permitiendo la búsqueda regular para encontrar A::onFoo().

+0

+1 - Buena explicación. – Mahesh

7

Este es el nombre que oculta, básicamente solo las anulaciones declaradas existen en B y las otras sobrecargas en A están ocultas.

2

Los métodos en las clases A y B deben ser públicos. Eso, y te faltan puntos y comas al final de cada declaración de clase.

class A { 
public: 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

class B : public A { 
public: 
    virtual void onFoo(int i) {} 
}; 

class C : public B { 
}; 


int main() { 
    C* c = new C(); 
    c->onFoo(); //Compile error - doesn't exist 
} 
+0

Esos son puntos válidos, pero su "corrección" tampoco compila. –

1

se le olvidó public: modificador antes de métodos, tanto en la clase A y B. Por lo tanto OnFoo método es privada y por lo tanto no es visible en cualquier lugar fuera de estas clases.

+0

Whoops: ese no era el problema, solo me transcribía el problema. Editado para corregir –

12

Si desea que los miembros de la clase base a la sobrecarga de miembros de la clase derivada, que desea utilizar using:

struct A 
{ 
    virtual void onFoo() {} 
    virtual void onFoo(int i) {} 
}; 

struct B : A 
{ 
    using A::onFoo; 
    virtual void onFoo(int i) {} 
}; 

struct C : B 
{ 
}; 


int main() 
{ 
    C* c = new C(); 
    c->onFoo(); 
} 
-2

Creo que se ha perdido la adición de esto en class B:

struct B : A 
{ 
    using A::onFoo; 
    virtual void onFoo(int i) {} 
    void onFoo() {} //This line missing in your code. 
}; 

Ahora bien, esto compila!

Cuestiones relacionadas