2009-05-13 17 views
18

Supongamos que tengo la función virtual foo() en la clase B, y necesito un comportamiento ligeramente diferente en una de las clases derivadas de B, clase D. ¿Es correcto crear una función primordial D :: foo(), y llame a B :: foo() desde allí, después del tratamiento de caso especial? De esta manera:Llamada a la función anulada de la función de anulación

void D::foo() 
{ 
    if (/*something*/) 
    // do something 
    else 
    B::foo(); 
} 

No estoy preguntando si eso funcionaría, sé que lo hará. Quiero saber si es correcto en términos de un buen OOD.

Respuesta

17

Esto está perfectamente bien. De hecho, la forma canónica de realizar algunas operaciones es llamar al método de la clase base, y luego hacer lo que sea (o al revés). Estoy pensando en operator= aquí. Los constructores generalmente trabajan de esa manera, incluso si esto está un poco disfrazado en la lista de inicialización.

4

Sí, lo es.

+3

típica, ampliamente utilizado Común, estándar, normal,. De hecho, es absolutamente esencial poder hacer esto. –

1

He visto marcos de GUI usar esto para recurrir a la implementación predeterminada de la clase base que contenía el código para señalar errores/arrojar una excepción/devolver un valor genérico.

5

Sí, está totalmente de acuerdo siempre que no esté infringiendo el Principio de Sustitución de Liskov.

0

Sí, es lo que su compilador hace por usted cada vez que genera un constructor y un destructor: llamando al de la madre, por ejemplo. A menudo confío en ese "truco" en mi propio código.

1

Está bien. La sintaxis que has dado también se puede usar para desactivar temporalmente el polimorfismo, es decir, cuando llamas a obj-> B :: foo() el método se elegirá de la clase B independientemente de si foo() es virtual o no y si obj es instancia de B o no (debe ser una instancia de la clase que se extiende B).

+0

No se puede garantizar que la función no sea llamada desde una subclase de _B_, en cuyo caso no está activando absolutamente nada. – xtofl

+0

@xtofl: Usted dice que si tengo B extiende A, C extiende B, es decir, una jerarquía de clase A B :: foo() para llamar a A :: foo()? –

+0

@xtolf: Acabo de verificar mi respuesta y parece ser correcta. –

0

Está bien llamar a la implementación de base, pero hacerlo condicionalmente lo aleja de la semántica del constructor, al contrario de lo que se ha sugerido en otras respuestas.

es posible que encuentre fragile base class problema de dos maneras:

  • Al asumir B::foo() proporciona un comportamiento común para toda la jerarquía (es decir, olvidando el método no siempre se llama)
  • problemas desagradables en función de lo // do something en realidad lo hace!

Para completar, vamos a mencionar un enfoque de diseño simétrico: Template pattern (implementación base llamar sub-parte específica)

Cuestiones relacionadas