C ++: виртуальные функции, которые должны вызывать один и тот же код? - PullRequest
5 голосов
/ 09 января 2012

У меня есть базовый класс и классы, производные от него.Базовый класс Controllable действует как интерфейс для цикла ввода, и другие классы наследуются от него, чтобы получить место в этом цикле для получения событий, например, при нажатии клавиши.

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

Поскольку класс Button обрабатывает события из очереди событий, установка его в неактивное состояние (которое выводит его из цикла ввода) может привести к пропуску важных событий, таких как нажатие клавиши,поэтому ему нужен дополнительный код, чтобы перевести его в дружественное неактивное состояние, если оно когда-нибудь снова станет активным.

Мой вопрос , как лучше всего обеспечить, чтобы setActive всегда имел ожидаемый эффект переключения m_active в правильное состояние, в то же время не требуя производногоклассы, чтобы определить это, если они не должны прикрепить дополнительный необходимый код?

Ответы [ 5 ]

9 голосов
/ 09 января 2012

Оставьте метод setActive не виртуальным, а затем определите отдельный метод protected activeChanged, который дочерние классы могут переопределить

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

При таком подходе внешний интерфейс public поддерживается отдельно от внутреннего защищенного интерфейса, предназначенного для дочерних классов.

6 голосов
/ 09 января 2012

Один из способов сделать это - определить виртуальные методы «pre» и «post»:

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

Обратите внимание, что метод setActive() является , а не виртуальным в этой технике.

2 голосов
/ 09 января 2012

По сути, ваш кейс изготовлен на заказ для Шаблонный шаблон дизайна шаблона .

1 голос
/ 09 января 2012

Мои 2 цента: разделите ваше поведение на 2 задачи:

virtual doActive(){}; //doNothing
void setActive (bool state) {
    m_active = state;
    doActive();
}
1 голос
/ 09 января 2012

Как насчет сделать setActive() не виртуальным, но вместо этого добавить второго виртуального члена (например, onSetActive()), который называется setActive()?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...