2012-01-09 15 views
5

Tengo una clase base y clases que derivan de ella. La clase base Controllable actúa como una interfaz para un bucle de entrada, y otras clases derivan de ella para obtener un lugar en ese bucle para obtener eventos como si se presionara una tecla.C++: ¿funciones virtuales que necesitan llamar al mismo código?

class Controllable{ 
public: 
    virtual void setActive(bool state) { m_active = state; } 
    virtual void input(Event & e) =0; 
private: 
    bool m_active; 
}; 

class Button : public Controllable{ 
public: 
    void setActive(bool state){ /*do extra work*/ m_active = state; } 
    void input(Event & e) override; 
}; 

Desde los Button clase aborda los acontecimientos desde una cola de eventos, poniéndolo al inactivo (que lo lleva fuera del circuito de entrada) puede provocar que se pierda eventos importantes como una clave siendo sin prensar, por lo que necesita adicional código para ponerlo en un estado amistoso inactivo si alguna vez vuelve a activarse más tarde.

Mi pregunta, ¿cuál es la mejor manera de asegurar que setActive siempre tiene el efecto deseado de cambiar m_active al estado correcto, mientras que al mismo tiempo, que no requiere que las clases derivadas para definir a menos que necesitan para fijar adicional código necesario?

+0

Tienes ';' '}' después de las funciones, ver por ellos. –

+0

Mr.TAMER - ¡arreglado! Tengo una picazón bonita; dedo –

Respuesta

9

Mantenga el setActive método no virtual y luego definir un protected método separado activeChanged que las clases hijas pueden anular

class Controllable{ 
public: 
    void setActive(bool state) { m_active = state; activeChanged(state); } 
    virtual void input(Event & e) = 0; 
protected: 
    virtual void activeChanged(bool newState) {} 
private: 
    bool m_active; 
} 

class Button : public Controllable{ 
protected: 
    void activeChanged(bool newState){ /*do extra work*/ } 
public: 
    void input(Event & e); 
}; 

Con este enfoque desea mantener el externo pública interfaz separado del interna protegida interfaz destinada a clases de niños.

+0

Gracias! No pensé en usar un método no virtual de esta manera. Tengo varias otras clases base que podrían beneficiarse de este tipo de tratamiento. –

+0

'activeChanged' debe ser privado, no estar protegido, ya que las clases derivadas nunca necesitarán llamar a la implementación de la clase base, solo la anulará. – ildjarn

+0

Minor "error": llamará a 'activeChanged()' a pesar de su nombre, incluso sin un cambio en el estado (como 'm_active' se evalúa como verdadero y llama' setActive (true) 'de nuevo). – Mario

1

¿Qué hay de hacer que setActive() no sea virtual pero en su lugar agregue un segundo miembro virtual (por ejemplo, onSetActive()) llamado por setActive()?

6

Una forma de hacer esto es definir "pre" y "post métodos virtuales":

class Controllable{ 
public: 
    void setActive(bool state) { 
     preSetActive(m_active, state); 
     m_active = state; 
     postSetActive(m_active); 
    }; 
    virtual void input(Event & e) =0; 
protected: 
    virtual void preSetActive(bool oldState, bool newState) {} 
    virtual void postSetActive(bool newState) {} 
private: 
    bool m_active; 
} 

en cuenta que el método es setActive()no virtual en esta técnica.

+0

Oh genial. Tener dos funciones antes y después puede ser exagerado en este caso, pero tengo algunas otras clases para las cuales sería perfecto. ¡Gracias! –

1

Mis 2 centavos: dividir su comportamiento entre 2 tareas:

virtual doActive(){}; //doNothing 
void setActive (bool state) { 
    m_active = state; 
    doActive(); 
} 
Cuestiones relacionadas