función virtual pura con implementación


Mi entendimiento básico es que no hay implementación para una función virtual pura, sin embargo, me dijeron que podría haber implementación para una función virtual pura.

class A {
public:
    virtual void f() = 0;
};

void A::f() {
    cout<<"Test"<<endl;
}

¿Está bien el código anterior?

¿Cuál es el propósito de convertirla en una función virtual pura con una implementación?

Author: Eight, 2010-01-18

8 answers

Una función pura virtual debe implementarse en un tipo derivado que se instanciará directamente, sin embargo, el tipo base todavía puede definir una implementación. Una clase derivada puede llamar explícitamente a la implementación de la clase base (si los permisos de acceso lo permiten) usando un nombre de ámbito completo (llamando a A::f() en su ejemplo-si A::f() eran public o protected). Algo como:

class B : public A {

    virtual void f() {
        // class B doesn't have anything special to do for f()
        //  so we'll call A's

        // note that A's declaration of f() would have to be public 
        //  or protected to avoid a compile time problem

        A::f();
    }

};

El caso de uso que se me ocurre es cuando hay un defecto más o menos razonable comportamiento, pero el diseñador de clases quiere que ese tipo de comportamiento predeterminado se invoque solo explícitamente. También puede ser el caso de lo que desea que las clases derivadas realicen siempre su propio trabajo, pero también sean capaces de llamar a un conjunto común de funcionalidad.

Tenga en cuenta que a pesar de que está permitido por el lenguaje, no es algo que veo comúnmente utilizado (y el hecho de que se puede hacer parece sorprender a la mayoría de los programadores de C++, incluso a los experimentados).

 180
Author: Michael Burr,
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
2015-12-18 18:49:02

Para ser claro, está malinterpretando lo que significa = 0; después de una función virtual.

= 0 significa que las clases derivadas deben proporcionar una implementación, no es que la clase base no pueda proporcionar una implementación.

En la práctica, cuando marca una función virtual como pura (=0), tiene muy poco sentido proporcionar una definición, porque nunca se llamará a menos que alguien lo haga explícitamente a través de Base::Function(...) o si el constructor de la clase base llama al función en cuestión.

 62
Author: Terry Mahaffey,
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-01-18 21:55:27

La ventaja de esto es que obliga a los tipos derivados a anular el método, pero también proporciona una implementación predeterminada o aditiva.

 20
Author: JaredPar,
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-01-18 20:49:31

Si tienes código que debería ser ejecutado por la clase derivante, pero no quieres que sea ejecutado directamente -- y quieres forzarlo a ser sobreescrito.

Su código es correcto, aunque en general esto no es una característica de uso frecuente, y por lo general solo se ve cuando se intenta definir un destructor virtual puro {en ese caso debe proporcionar una implementación. Lo curioso es que una vez que se deriva de esa clase no es necesario anular el destructor.

Por lo tanto el único uso sensato de funciones virtuales puras es especificar un destructor virtual puro como una palabra clave "no final".

El siguiente código es sorprendentemente correcto:

class Base {
public:
  virtual ~Base() = 0;
};

Base::~Base() {}

class Derived : public Base {};

int main() { 
  // Base b; -- compile error
  Derived d; 
}
 16
Author: Kornel Kisielewicz,
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-01-18 21:22:00

Tendrías que darle un cuerpo a un destructor virtual puro, por ejemplo :)

Léase: http://cplusplus.co.il/2009/08/22/pure-virtual-destructor /

(Enlace roto, use archivo)

 5
Author: rmn,
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-09-20 14:27:42

Sí, esto es correcto. En su ejemplo, las clases que se derivan de A heredan tanto la interfaz f () como una implementación predeterminada. Pero fuerzas a las clases derivadas a implementar el método f () (incluso si es solo para llamar a la implementación predeterminada proporcionada por A).

Scott Meyers discute esto en Effective C++ (2nd Edition) Item #36 Diferenciar entre herencia de interfaz y herencia de implementación. El número de artículo puede haber cambiado en la última edición.

 4
Author: Yukiko,
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-01-18 21:10:36

Las funciones virtuales puras con o sin un cuerpo simplemente significan que los tipos derivados deben proporcionar su propia implementación.

Los cuerpos de función virtuales puros en la clase base son útiles si sus clases derivadas quieren llamar a su implementación de clase base.

 4
Author: Brian R. Bondy,
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-04-09 18:12:42

La sintaxis 'virtual void foo() =0;' no significa que no puedas implementar foo() en la clase actual, sí puedes. Tampoco significa que deba implementarlo en clases derivadas. Antes de abofetearme, observemos el Problema del Diamante.: (Código implícito, eso sí).

class A
{
public: 
    virtual void foo()=0;
    virtual void bar();
}

class B : public virtual A
{
public:
    void foo() { bar(); }
}

class C : public virtual A
{
public:
    void bar();
}

class D : public B, public C
{}

int main(int argc, const char* argv[])
{
    A* obj = new D();
    **obj->foo();**
    return 0;
}

Ahora, la invocación obj->foo() resultará en B::foo() y luego C::bar().

Ya ves... los métodos virtuales puros no tienen que ser implementados en clases derivadas (foo () no tiene implementación en clase C - el compilador compilará) En C++ hay muchas lagunas.

Espero poder ayudar: -)

 1
Author: Nir Hedvat,
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
2015-03-24 20:55:57