llamada a función virtual desde la clase base


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;  
}

¿De cuál g() se llamará Base::f()? Base::g() o Derived::g()?

Gracias...

Author: Gal Goldman, 2008-12-29

8 answers

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

Base::g();

En su lugar. Si desea llamar a la derivada, pero aún desea que se llame a la versión base, organice que la versión derivada de g llame a la versión base en su primera instrucció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 utiliza en el patrón de diseño del método de plantilla. Para C++, es mejor conocido como Interfaz no Virtual. Es ampliamente utilizado también en la biblioteca estándar de C++ (los búferes de flujo de C++, por ejemplo, tienen funciones pub... que llaman a funciones virtuales que hacen el trabajo real. Por ejemplo pubseekoff llama al protegido seekoff). Escribí un ejemplo de eso en esta respuesta: ¿Cómo validas el estado interno de un objeto?

 50
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:39

Es el Derivado::g, a menos que llame a g en el constructor de Base. Debido a que el constructor Base es llamado antes de que se construya el objeto Derivado, Derived::g no puede ser llamado lógicamente porque podría manipular variables que aún no han sido construidas, por lo que Base:: g será llamado.

 6
Author: Syed Lavasani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-19 04:18:01

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

Así que pBase = nuevo Derivado es válido.

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

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

Entonces vemos en el código que:

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

Bueno, llama Derive::g() porque es la g a la que pBase "apunta".

Respuesta: Derive:: g ()

 5
Author: Jacob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-28 20:56:32

Bueno... No estoy seguro de que esto deba compilar. Lo siguiente,

Base *pBase = new Derived;

No es válido a menos que tenga:

Class Derived : public Base

¿Es lo que quieres decir? Si esto es lo que querías decir,

pBase->f();

Entonces la pila de llamadas sería así:

Derived::f()
    Base::f()
        Derived::g()
 2
Author: user48956,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-29 19:20:54

Como ha definido g() como virtual, la g() más derivada será buscada en la vtable de la clase y llamada independientemente del tipo de código al que esté accediendo actualmente.

Consulte las preguntas frecuentes de C++ sobre funciones virtuales.

 1
Author: Thorsten79,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-29 10:15:35

Realmente ejecutando tu código muestra que Derived::g() es llamado.

 1
Author: KJAWolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-30 07:30:04

Creo que estás tratando de inventar Patrón de Método de Plantilla

 0
Author: Lazin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-29 10:06:30

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

Esto se debe a la inclusión de vtables dentro de 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 una vtable para Base y se crea una vtable para Derived, porque solo hay una vtable por clase. Debido a que pBase está llamando a una función que es virtual y anula, un puntero a la vtable para Derived es called. 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 la tabla v para ver qué g() usar. Debido a que el vpointer solo conoce g() en Derived, ese es el que usamos. Por lo tanto, Derived::g() se llama.

 0
Author: Jossie Calderon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-23 02:08:36