2010-08-22 9 views
5

Sé que esta pregunta debe haber sido cubierta un sinfín de veces, pero he buscado en las preguntas anteriores, y nada parece reventar.Llamando a la función virtual en la subclase de la superclase

Se trata de la herencia y las funciones virtuales i C++. Tengo un problema al llamar funciones virtuales en subclases de la superclase.

Déjeme dar un ejemplo. Comienzo con tres clases, que heredan el uno del otro.

class A { 

    void foo() { bar() } 
    virtual void bar() { } 

}; 

class B : public A { 

    virtual void bar() { } 

}; 

class C : public B { 

    virtual void bar() { // do something } 

}; 

Ahora quiero tener una variable declarada como B * pero instanciada como C *.

B* myObject = new C(); 
myObject->foo(); 

Cuando hago esto, y llamar a foo() en myObject, entonces A :: foo() está llamando bar(). Pero solo se llama a B :: bar(), no a C :: Bar() - que en realidad es myObject, a pesar de que está declarado como B, lo que de nuevo afecta que "// no haga nada" no se ejecuta.

¿Cómo le digo a A :: foo() que necesita ver la implementación más baja?

Tiene sentido?

// Trenskow

EDIT:

C :: Foo no es el problema. Foo es llamado en la clase A, ya que es el único lugar donde se implementa. El problema surge cuando A: Foo llama a Bar(). Luego se llama B: Bar y no C :: Bar.

Tal vez el problema es que en mi aplicación, solo me dan un puntero void * al objeto en A.

De esta manera:

void A:Foo(void *a) { 

    A* tmpA = static_cast<A*> (a); 
    tmpA->bar(); 

} 

Ahora el compilador piensa, que es un Tmpa R. Pero de alguna manera se las arregla para darse cuenta de que es un B *, y llama a B :: Bar, cuando en realidad tmpA es un C * y debería estar llamando a C :: Bar.

+1

Si ha publicado un código real, entonces podríamos decir que el problema es. No necesitas hacer nada especial. Si los errores de sintaxis son fijos, el código ('myObject-> foo();') llamará a 'C :: bar()'. – UncleBens

+0

... pero si tuviera que adivinar, o 'C' en realidad no anula' bar' (con una firma diferente), o está cortando el objeto en algún lugar (haciendo algo como '* variable = * myObject;' – UncleBens

+0

Todavía no lo compro. ¿Por qué no se llamaría a C :: bar()? ¿Puedes publicar el código real? – EboMike

Respuesta

5

Lo siguiente imprime "A :: foo C :: bar" como se esperaba. ¿Estás obteniendo algo diferente? B::bar nunca se llama porque C es el tipo de tiempo de ejecución real del objeto. En C::bar, puede llamar al B::bar explícitamente agregando B::bar(); a su cuerpo.

#include <iostream> 
using namespace std; 

class A { 
public: 
    void foo() { cout << "A::foo "; bar(); } 
    virtual void bar() { } 
}; 

class B : public A { 
public: 
    virtual void bar() { cout << "B::bar" << endl; } 
}; 

class C : public B { 
public: 
    virtual void bar() { cout << "C::bar" << endl; } 
}; 

int main() 
{ 
    B* c = new C(); 
    c->foo(); 
    return 0; 
} 
0

Suponiendo que usted ha escrito mal el último bloque de código y los nombres coinciden con:

B* variable = new C(); 
variable->foo(); 

A continuación, se llama al método C :: Foo o si está utilizando una terriblemente mal compilador.

(Esto también da por supuesto que en realidad no tiene un error de compilación en C :: Foo, y que el comentario es en realidad algo así como std::cout << "Hi mom!" << std::endl;)

0

No quiere decir:

B* myObject = new C(); 
myObject->foo(); // not variable->foo() 

class A 
{ 
public: 
    void foo() { bar(); } 
    virtual void bar() { std::cout << "A"; }; 
}; 

class B : public A 
{ 
public: 
    virtual void bar() { std::cout << "B";}; 
}; 

class C : public B 
{ 
public: 
    virtual void bar() { std::cout << "C"; } 
}; 

Esto imprime 'C' como se esperaba.

+0

Oh, sí, sí. Cambió el nombre de la variable en una edición, no solo para llamarlo variable. Debe haber olvidado la segunda línea. Editado – Trenskow

0

No sigo. ¿Estás diciendo

Pero sólo B :: bar() se llama, no C :: bar()

No. Usted ha invocado el constructor de la clase C, lo que significa que la viable hace que bar() señale a C :: bar(), por lo que llamar a foo() en este caso iría directamente a C :: bar().

Si desea forzar un foo ::() para llamar explícitamente única aplicación de A, que puede hacer que con sólo escribir

void foo() { A::bar(); } 

¿Qué es exactamente estás tratando de hacer?

0

¿qué compilador estás usando? Visual Studio (IIRC) por lo general tiene la información del tipo de tiempo de ejecución desactivada de forma predeterminada, así que tal vez sea algo así de simple.

2
void A:Foo(void *a) { 

    A* tmpA = static_cast<A*> (a); 
    tmpA->bar(); 

} 

Comportamiento indefinido. No puedes convertir un B * en un vacío *, luego lanzar ese vacío * de regreso a un A *. Si quieres que funcione correctamente, debes abandonar el vacío *. Alternativamente, puedes probar dynamic_cast.

+0

O lanzas B * a A * primero y luego emites A * para anular *. – Tomek

Cuestiones relacionadas