2010-04-09 12 views
38

Recientemente llegué a saber que en C++ las funciones virtuales puras pueden tener un cuerpo opcionalmente.Casos de uso de funciones virtuales puras con el cuerpo?

¿Cuáles son los casos de uso del mundo real para tales funciones?

+2

parece una estafa de http://stackoverflow.com/questions/2089083/pure-virtual-function-with-implementation – patros

+5

@patros: ninguna de las respuestas en ese hilo describe un * caso de uso del mundo real *. Entonces, no, no creo que esto sea una tontería. – missingfaktor

Respuesta

31

El clásico es un destructor virtual puro:

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

abstract::~abstract() {} 

Haces que pura porque no hay nada más que hacer así, y desea que la clase sea abstracta, pero hay que proporcionar una implementación sin embargo, debido los destructores de las clases derivadas llaman a los tuyos explícitamente. Sí, lo sé, un ejemplo de libro de texto bastante tonto, pero como tal es un clásico. Debe haber estado en la primera edición de The C++ Programming Language.

De todos modos, no recuerdo haber necesitado realmente la capacidad de implementar una función virtual pura. Para mí, parece ser que la única razón por la cual esta función está ahí es porque tendría que haber sido explícitamente rechazada y Stroustrup no vio una razón para eso.

Si alguna vez siente que necesita esta característica, probablemente esté en el camino equivocado con su diseño.

+3

Un problema que puede tener un infractor (para el registro, no voté negativamente) es que realmente no hay una razón fuerte para tener un destructor virtual puro. Si hay otra función virtual pura, no hay ninguna razón para que el dtor sea puramente virtual (aunque seguramente debería ser virtual).Si el dtor es la única función virtual pura, entonces realmente no es necesario que la clase sea abstracta. –

+1

@Michael: Conozco esta crítica. (De hecho, escribí más o menos eso en mi respuesta.) El problema es que no puedo pensar en ninguna buena razón para implementar una función virtual pura. Como escribí, si sientes que necesitas hacer eso, es muy probable que estés en el camino equivocado. – sbi

+0

@MichaelBurr eso es ridículo. se está olvidando de todas las otras cosas que no son métodos. puede tener una clase abstracta base que le proporcione algún campo de datos (porque por qué duplicar cuándo va a ser compartido por derivadas), y declarar una interfaz o un concepto al mismo tiempo. –

27

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

Las entidades virtuales puras en la clase base son útiles si sus clases derivadas quieren llamar a la implementación de su clase base.

8

Un caso de uso es llamar a la función virtual pura desde el constructor o el destructor de la clase.

+1

+1: Este es de hecho el caso principal. Algunos podrían decir el único caso. –

+0

Pero no existe un constructor virtual puro, que su publicación parece implicar. –

+3

@John: Lo leí diferente. Sin embargo, creo que llamar a funciones virtuales, puras o no, de ctors o detors es una práctica bastante cuestionable de todos modos. – sbi

4

La única diferencia de la función virtual con el cuerpo y la función virtual pura con el cuerpo es que la existencia de la segunda evita la creación de instancias. No puede marcar el resumen de clase en C++.

16

Una razón por la que una clase base abstracta (con una función virtual pura) podría proporcionar una implementación para una función virtual pura que declara es permitir que las clases derivadas tengan un 'predeterminado' fácil que puedan elegir usar. No hay una gran ventaja sobre esto sobre una función virtual normal que puede ser opcionalmente anulada; de hecho, la única diferencia real es que usted está forzando a la clase derivada a ser explícita sobre el uso de la implementación de la clase base 'predeterminada'. :

class foo { 
public: 
    virtual int interface(); 
}; 

int foo::interface() 
{ 
    printf("default foo::interface() called\n"); 
    return 0; 
}; 


class pure_foo { 
public: 
    virtual int interface() = 0; 
}; 

int pure_foo::interface() 
{ 
    printf("default pure_foo::interface() called\n"); 
    return 42; 
} 

//------------------------------------ 

class foobar : public foo { 
    // no need to override to get default behavior 
}; 

class foobar2 : public pure_foo { 
public: 
    // need to be explicit about the override, even to get default behavior 
    virtual int interface(); 
}; 

int foobar2::interface() 
{ 
    // foobar is lazy; it'll just use pure_foo's default 
    return pure_foo::interface(); 
} 

no estoy seguro de que hay una gran cantidad de beneficios - tal vez en casos donde un diseño comenzó con una clase abstracta, con el tiempo encontrado que muchas de las clases concretas derivadas estaban aplicando el mismo comportamiento , por lo que decidieron mover ese comportamiento a una implementación de clase base para la función virtual pura.

Supongo que también podría ser razonable poner un comportamiento común en la implementación de la clase base de la función virtual pura que las clases derivadas podrían modificar/mejorar/aumentar.

+0

@RichardGeorge: ¿puedes explicar qué no se está ejecutando correctamente? Está funcionando como esperaba, pero tal vez estés viendo un caso de uso diferente que yo. –

+0

@Micheal, funciona bien, estoy un poco desordenado con mi propio caso de uso, +1 para ti. –

7

El todopoderoso Herb Sutter, ex presidente del comité estándar de C++, did give 3 scenarios, donde podría considerar proporcionar implementaciones para métodos virtuales puros.

Tengo que decirlo personalmente, no encuentro ninguno de ellos convincente, y generalmente considero que esta es una de las verrugas semánticas de C++.Parece que C++ hace todo lo posible para construir y desgarrar cuadros visuales de padres abstractos, que los expone brevemente solo durante la construcción/destrucción del niño, and then los expertos de la comunidad recomiendan never to use them por unanimidad.

+1

Ese artículo de Sutter es excelente. Aclarado algunas ideas oscuras para mí. – DarenW

+0

No veo la relación con los vtables padre abstracto. – curiousguy

2

Esta pregunta realmente puede ser confusa al aprender OOD y C++. Personalmente, una cosa que constantemente me venía a la mente era algo así como: Si necesitaba una función Pure Virtual para tener también una implementación, ¿por qué hacerlo "Puro" en primer lugar? ¿Por qué no simplemente dejarlo solo como "Virtual" y haber derivado ambos beneficios y anular la implementación base?

La confusión viene al hecho de que muchos desarrolladores consideran el no cuerpo/implementación como el principal objetivo/beneficio de definir una función virtual pura. ¡Esto no es verdad! La ausencia de cuerpo es en la mayoría de los casos una consecuencia lógica de tener una función virtual pura. ¡El principal beneficio de tener una función virtual pura es DEFINIENDO UN CONTRATO! Al definir una función virtual pura, desea FORZAR cada derivado para SIEMPRE proporcionar su PROPIA IMPLEMENTACIÓN de la función. Este "aspecto CONTRATO" es muy importante, especialmente si está desarrollando algo así como una API pública. Hacer que la función sea solo virtual no es suficiente porque los derivados ya no están obligados a proporcionar su propia implementación, por lo tanto, puede perder el aspecto del contrato (esto puede ser limitante en el caso de una API pública). Como se dice comúnmente: "Las funciones virtuales PUEDEN sobrescribirse, las funciones virtuales puras DEBEN sobrescribirse". Y en la mayoría de los casos, los contratos son conceptos abstractos, por lo que no tiene sentido que las funciones virtuales puras correspondientes tengan alguna implementación.

Pero a veces, y como la vida es extraña, es posible que desee establecer un contrato sólido entre los derivados y también quiere que se beneficien de alguna manera de la implementación predeterminada y especifiquen su propio comportamiento para el contrato. Incluso si la mayoría de los autores de libros recomiendan evitar estas situaciones, ¡el lenguaje necesario para proporcionar una red de seguridad para evitar lo peor! Una simple función virtual no sería suficiente, ya que podría existir el riesgo de escapar del contrato. Entonces, la solución que C++ proporcionó fue permitir que las funciones virtuales puras también pudieran proporcionar una implementación predeterminada.

El artículo de Sutter citado anteriormente ofrece casos de uso interesantes de tener funciones Pure Virtual con cuerpo.

+0

¿Dónde está el artículo de Sutter? No lo veo más que su observación en la oración final * "... el artículo de Sutter citado anteriormente ..." *. – jww

Cuestiones relacionadas