La pregunta en el tema sugiere una confusión bastante común. La confusión es bastante común, que las preguntas frecuentes de C ++ abogaron contra el uso de virtuales privados, durante mucho tiempo, porque la confusión parecía ser algo malo.
Entonces, para deshacerse de la confusión primero: Sí, las funciones virtuales privadas pueden anularse en las clases derivadas. Los métodos de clases derivadas no pueden llamar a funciones virtuales desde la clase base, pero pueden proporcionar su propia implementación para ellas. Según Herb Sutter, tener una interfaz pública no virtual en la clase base y una implementación privada que se puede personalizar en las clases derivadas, permite una mejor "separación de la especificación de la interfaz de la especificación del comportamiento personalizable de la implementación". Puede leer más al respecto en su artículo "Virtualidad" .
Sin embargo, hay una cosa más interesante en el código que presentó, que merece más atención, en mi opinión. La interfaz pública consta de un conjunto de funciones no virtuales sobrecargadas y esas funciones llaman funciones virtuales no públicas, no sobrecargadas. Como es habitual en el mundo de C ++, es un idioma, tiene un nombre y, por supuesto, es útil. El nombre es (¡sorpresa, sorpresa!)
"Públicos no virtuales sobrecargados Llamadas virtuales no sobrecargadas protegidas"
Ayuda a gestionar adecuadamente la regla de ocultación . Puede leer más sobre esto aquí , pero trataré de explicarlo en breve.
Imagine que las funciones virtuales de la Engine
clase también son su interfaz y es un conjunto de funciones sobrecargadas que no es puramente virtual. Si fueran puramente virtuales, todavía se podría encontrar el mismo problema, como se describe a continuación, pero más abajo en la jerarquía de clases.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Ahora supongamos que desea crear una clase derivada y necesita proporcionar una nueva implementación solo para el método, que toma dos entradas como argumentos.
class MyTurbochargedV8 : public Engine
{
public:
// To prevent SetState( int var, bool val ) from the base class,
// from being hidden by the new implementation of the other overload (below),
// you have to put using declaration in the derived class
using Engine::SetState;
void SetState( int var, int val ) {/*new implementation*/}
};
Si olvidó poner la declaración de uso en la clase derivada (o redefinir la segunda sobrecarga), podría meterse en problemas en el siguiente escenario.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Si no evitaste la ocultación de los Engine
miembros, la declaración:
myV8->SetState(5, true);
llamaría void SetState( int var, int val )
desde la clase derivada, convirtiendo true
a int
.
Si la interfaz no es virtual y la implementación virtual no es pública, como en su ejemplo, el autor de la clase derivada tiene un problema menos en el que pensar y simplemente puede escribir
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};
La función virtual pura privada es la base del idioma de la interfaz no virtual (OK, no siempre es puramente virtual, pero todavía es virtual allí). Por supuesto, esto también se usa para otras cosas, pero creo que esto es muy útil (: en dos palabras: en una función pública, podría poner algunas cosas comunes (como el registro, las estadísticas, etc.) al principio y al final de la función y luego, "en el medio" para llamar a esta función virtual privada, que será diferente para la clase derivada específica.
Virtual puro : solo obliga a las clases derivadas a implementarlo.
EDITAR : Más sobre esto: Wikipedia :: NVI-idiom
fuente
Bueno, por un lado, esto permitiría que una clase derivada implemente una función que la clase base (que contiene la declaración de función virtual pura) puede llamar.
fuente
EDITAR: declaraciones aclaradas sobre la capacidad de anulación y la capacidad de acceder / invocar.
Podrá anular esas funciones privadas. Por ejemplo, el siguiente ejemplo artificial funciona ( EDITAR: hace que el método de clase derivada sea privado y suelte la invocación del método de clase derivada
main()
para demostrar mejor la intención del patrón de diseño en uso ):Private
virtual
Los métodos en una clase base como los de su código generalmente se usan para implementar el patrón de diseño del Método de plantilla . Ese patrón de diseño le permite a uno cambiar el comportamiento de un algoritmo en la clase base sin cambiar el código en la clase base. El código anterior donde se invocan los métodos de clase base a través de un puntero de clase base es un ejemplo simple del patrón de Método de plantilla.fuente
Engine
yDerivedEngine
no tiene nada que ver con lo queDerivedEngine
puede o no puede anular (o acceder, para el caso).El método virtual privado se utiliza para limitar el número de clases derivadas que pueden anular la función dada. Las clases derivadas que tienen que anular el método virtual privado deberán ser amigos de la clase base.
Se puede encontrar una breve explicación de DevX.com .
EDITAR Un método virtual privado se utiliza de manera efectiva en el Patrón de método de plantilla . Las clases derivadas pueden anular el método virtual privado, pero las clases derivadas no pueden llamar a su método virtual privado de clase base (en su ejemplo,
SetStateBool
ySetStateInt
). Solo la clase base puede llamar efectivamente a su método virtual privado ( solo si las clases derivadas necesitan invocar la implementación base de una función virtual, hacer que la función virtual esté protegida ).Se puede encontrar un artículo interesante sobre la virtualidad .
fuente
friend
de la clase base. Qt adoptó el mismo enfoque cuando implementaron su modelo de documento DOM XML.TL; respuesta DR:
Puede tratarlo como otro nivel de encapsulación, en algún lugar entre protegido y privado : no puede llamarlo desde la clase secundaria, pero puede anularlo.
Es útil al implementar el patrón de diseño del Método de plantilla . Puede usar protegido , pero privado junto con virtual puede considerarse como una mejor opción, debido a una mejor encapsulación.
fuente