c++ - online - ¿Casos de uso de funciones virtuales puras con cuerpo?
polimorfismo c++ (7)
Recientemente llegué a saber que en C ++ las funciones virtuales puras pueden tener opcionalmente un cuerpo.
¿Cuáles son los casos de uso en el mundo real para tales funciones?
El clásico es un destructor virtual puro:
class abstract {
public:
virtual ~abstract() = 0;
};
abstract::~abstract() {}
Lo hace puro porque no hay nada más que lo haga, y quiere que la clase sea abstracta, pero sin embargo, tiene que proporcionar una implementación, porque los destructores de las clases derivadas llaman a los suyos 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. A mí me parece que la única razón por la que esta característica está allí es porque habría tenido que ser explícitamente rechazada y Stroustrup no vio una razón para eso.
Si alguna vez siente que necesita esta función, probablemente esté en el camino equivocado con su diseño.
El todopoderoso Herb Sutter, ex presidente del comité de estándares de C ++, dio 3 escenarios en los que podría considerar proporcionar implementaciones para métodos virtuales puros.
Tengo que decirlo personalmente, ninguno de ellos me parece convincente y, en general, considero que es una de las verrugas semánticas de C ++. Parece que C ++ hace todo lo posible por crear y desarmar vtables abstractas, lo que las expone brevemente solo durante la construcción / destrucción de niños, y luego los expertos de la comunidad recomiendan unánimemente que nunca los usen .
Esta pregunta puede ser realmente confusa cuando se aprende OOD y C ++. Personalmente, una cosa que constantemente me vino a la mente fue algo como: si necesitaba una función Pure Virtual para tener también una implementación, entonces, ¿por qué hacerla "Pure" en primer lugar? ¿Por qué no solo dejarlo solo "Virtual" y haber derivado tanto el beneficio como la anulación de la implementación base?
La confusión llega al hecho de que muchos desarrolladores consideran que ningún cuerpo / implementación es el objetivo / beneficio principal 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 ¡DEFINIR UN CONTRATO! Al definir una función virtual pura, usted quiere FUERZA que cada derivado derivado SIEMPRE proporcione su propia IMPLEMENTACIÓN DE la función. Este "aspecto de CONTRATO" es muy importante, especialmente si está desarrollando algo 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 ser anuladas, las funciones virtuales puras DEBEN ser anuladas". 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 debido a que la vida es extraña, es posible que desee establecer un contrato sólido entre los derivados y también que se beneficien de alguna manera con la implementación predeterminada, al tiempo que especifica su propio comportamiento para el contrato. Incluso si la mayoría de los autores de libros recomiendan evitar meterse en 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 haber riesgo de escapar del contrato. Por lo tanto, la solución que proporcionó C ++ fue permitir que las funciones virtuales puras también puedan proporcionar una implementación predeterminada.
El artículo de Sutter citado anteriormente ofrece interesantes casos de uso de funciones de Pure Virtual con cuerpo.
La única diferencia de la función virtual con cuerpo y la función virtual pura con cuerpo es que existe una segunda instancia de prevención. No puedes marcar el resumen de la clase en c ++.
Las funciones virtuales puras con o sin un cuerpo simplemente significan que los tipos derivados deben proporcionar su propia implementación.
Los cuerpos de funciones virtuales puras en la clase base son útiles si las clases derivadas desean llamar a la implementación de la clase base.
Un caso de uso es llamar a la función virtual pura desde el constructor o el destructor de la clase.
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 "valor predeterminado" fácil que pueden elegir usar. Esto no ofrece muchas ventajas sobre una función virtual normal que puede ser anulada opcionalmente, de hecho, la única diferencia real es que está obligando 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 haya muchos beneficios, tal vez en los casos en que un diseño comenzó con una clase abstracta, luego, con el tiempo, descubrí que muchas de las clases concretas derivadas implementaban el mismo comportamiento, por lo que decidieron mover ese comportamiento. en 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 se espera que las clases derivadas modifiquen / mejoren / aumenten.