virtuales puro puras polimorfismo multiple modificador herencia funciones entre ejemplo diferencia derivada clase c++ polymorphism virtual

puras - polimorfismo puro c++



llamada de funciĆ³n virtual de la clase base (8)

Digamos que tenemos:

Class Base { virtual void f(){g();}; virtual void g(){//Do some Base related code;} }; Class Derived : public Base { virtual void f(){Base::f();}; virtual void g(){//Do some Derived related code}; }; int main() { Base *pBase = new Derived; pBase->f(); return 0; }

¿Qué g() se llamará desde Base::f() ? Base::g() o Derived::g() ?

Gracias...


Bueno ... No estoy seguro de que esto deba compilarse. El seguimiento,

Base *pBase = new Derived;

no es válido a menos que tenga:

Class Derived : public Base

¿Quieres que quisieras decir? Si esto es querer, querías decir,

pBase->f();

Entonces la pila de llamadas sería así:

Derived::f() Base::f() Derived::g()




En realidad, ejecutar su código muestra que se llama Derived :: g ().


pBase es un puntero a una base. pBase = new Derived devuelve un puntero a Derived - Derived is-a Base.

Entonces pBase = new Derived es válido.

pBase hace referencia a una Base, por lo que verá Derivada como si fuera una Base.

pBase-> f () llamará Derive :: f ();

Entonces vemos en el código que:

Derive :: f () -> Base :: f () -> g () - pero ¿qué g?

Bueno, llama Derive :: g () porque ese es el g al que pBase "apunta".

Respuesta: Derive :: g ()


Es Derived :: g, a menos que llame a g en el constructor de Base. Como se llama al constructor Base antes de que se construya el objeto Derivado, Derived :: g no se puede llamar lógicamente porque podría manipular las variables que aún no se han construido, por lo que se llamará a Base :: g.


Se llamará al método de la clase derivada.

Esto se debe a la inclusión de tablas virtuales dentro de las clases que tienen funciones virtuales y clases que anulan esas funciones. (Esto también se conoce como despacho dinámico). Esto es lo que realmente está pasando: se crea un vtable para Base y se crea un vtable para Derived , porque solo hay un vtable por clase. Como pBase llama a una función que es virtual y se pBase se llama a un puntero al vtable para Derived . Llámalo d_ptr , también conocido como vpointer:

int main() { Base *pBase = new Derived; pBase->d_ptr->f(); return 0; }

Ahora el d_ptr llama a Derived::f() , que llama a Base::f() , que luego mira el vtable para ver qué g() usar. Debido a que vpointer solo conoce g() en Derived , ese es el que usamos. Por lo tanto, se llama Derived::g() .


Se llamará la g de la clase derivada. Si desea llamar a la función en la base, llame

Base::g();

en lugar. Si desea llamar al derivado, pero aún desea que se llame a la versión base, disponga que la versión derivada de g llame a la versión base en su primera declaración:

virtual void g() { Base::g(); // some work related to derived }

El hecho de que una función de la base puede llamar a un método virtual y el control se transfiere a la clase derivada se usa en el patrón de diseño del método de la plantilla. Para C ++, es mejor conocido como Non-Virtual-Interface . Se usa ampliamente también en la biblioteca estándar de C ++ (los búferes de flujo C ++, por ejemplo, tienen funciones pub... que llaman funciones virtuales que hacen el trabajo real. Por ejemplo, pubseekoff llama a la seekoff protegida). Escribí un ejemplo de eso en esta respuesta: ¿cómo se valida el estado interno de un objeto?