2012-04-20 14 views
5

La clase base A tiene una subclase B, y B tiene una subclase C. A implementa un método virtual doStuff(), B no, y C hace. De C, quiero llamar A 'ejecución de doStuff() s (Lo hago desde dentro C' ejecución de doStuff() s pero eso no debería realmente importa.) ¿Debo llamar a:Llamando métodos idénticos en las clases base

A::doStuff(); 

O:

B::doStuff(); 

El primero parece más claro porque se refiere a la implementación real. Por otro lado, el segundo podría ser más útil si luego decido que B necesita doStuff() de manera diferente que A. ¿Cuál es más estándar? ¿Cuál es más peligroso?

Me sorprendió un poco que B::doStuff() no disparara ninguna advertencia, pero supongo que por definición B tiene una implementación, incluso si es de la clase base. ¿La cadena de clases base y las implementaciones pueden ser arbitrariamente largas y complicadas? Por ejemplo, si tuviera A hasta Z, cada una de las subclases de la anterior, ¿podría haber implementaciones en algún lugar de la cadena, y llamar al método de cualquier clase simplemente subir la cadena hasta que encuentre una implementación?

Respuesta

2

Primero, con respecto al último párrafo, sí, tiene toda la razón.

El siguiente, para la pregunta principal:

Es una cuestión de lógica que debe ser tratado en una base de caso por caso. Usted es el único que puede decidir si desea llamar a la lógica desde B o desde A, incluso si B::doStuff() aún no está implementado. No hay una respuesta correcta.

Sin embargo, debe consultar el patrón de modelo. Supongo que si quieres C llamar algo desde A y luego decides que quieres D (hermano de C) para hacer lo mismo, estás duplicando el código. Así que tomaría un enfoque diferente:

class A 
{ 
private: 
    void doAStuff(); //doesn't have to be here 
public: 
    virtual void doStuff() 
    { 
     doAStuff(); 
    } 
    void doAStuffAndStuff(); 
    { 
     doAStuff(); 
     doStuff(); 
    } 
} 

class B : A 
{ 
public: 
    virtual void doStuff(); //or not 
} 

class C : B 
{ 
public: 
    virtual void doStuff(); 
} 

IMO esto es más intuitivo. Decir que tengo un A* a, no sé el tipo dinámico de a:

  • si quiero llamar doStuff() con la lógica de la clase más derivada, me llaman doStuff().
  • si quiero llamar a doStuff() con la lógica en la clase más derivada, pero también quiero la lógica de A, llamo a doAStuffAndStuff().

Estoy estableciendo este enfoque como una alternativa. No estoy diciendo que necesariamente se aplique a su caso, pero podría ser.

+0

Parece una alternativa muy ordenada y útil. – Luke

0

Llame B::doStuff. Aún mejor, no use diseños que requieran llamar a métodos de clases base explícitamente, si puede.Si es necesario, simule base.doStuff mediante alguna construcción de macros o alias para evitar exactamente ese tipo de errores. Puede definir un alias (y garantizar su presencia en tiempo de compilación) BaseType en clase y usar la sintaxis BaseType::doStuff.

que estaba un poco sorprendido de que B :: hacerTarea() no provocó ninguna advertencia, pero supongo que, por definición, B tiene una aplicación incluso si es de la clase base

Hay nada para advertir. Es en tu caso un escenario legal.

¿Puede la cadena de clases base y las implementaciones ser arbitrariamente larga y complicada

Sí se puede, pero no debe. Los diseños que requieren largas cadenas de herencia y contienen algún tipo de reglas ocultas, por lo general, se rompen los métodos de las clases base a las que se debe llamar.

Cuestiones relacionadas