Anne Quinn
Anne Quinn

Reputation: 13000

C++: Virtual functions that need to call the same code?

I have a base class and classes that derive from it. The base class Controllable acts as an interface for an input loop, and other classes derive from it to get a spot in that loop to get events like if a key is pressed.

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;
};

Since the Button class deals with events from an event queue, setting it to inactive (which takes it out of the input loop) may cause it to miss important events like a key being unpressed, so it needs extra code to put it into a friendly inactive state should it ever become active again later.

My question, what is the best way to ensure that setActive always has the intended effect of switching m_active to the correct state, while at the same time, not requiring derived classes to define it unless they need to attach extra needed code?

Upvotes: 5

Views: 196

Answers (5)

Anders Abel
Anders Abel

Reputation: 69260

Keep the setActive method non-virtual and then define a separate protected method activeChanged that the child classes can override

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);
};

With this approach you are keeping the external public interface separated from the internal protected interface intended for child classes.

Upvotes: 9

Alar
Alar

Reputation: 780

My 2 cents: split your behaviour between 2 tasks:

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

Upvotes: 1

Greg Hewgill
Greg Hewgill

Reputation: 993183

One way to do this is to define "pre" and "post" virtual methods:

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;
}

Note that the setActive() method is not virtual in this technique.

Upvotes: 6

Alok Save
Alok Save

Reputation: 206546

Basically your case is custom made for Template method design pattern.

Upvotes: 2

Mario
Mario

Reputation: 36487

How about making setActive() non-virtual but instead adding a second virtual member (e.g. onSetActive())that's called by setActive()?

Upvotes: 1

Related Questions