我有一个基类和派生自它的类。基类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
切换到正确状态的预期效果的最佳方法是什么,同时,不是除非需要附加额外需要的代码,否则需要派生类来定义它?
答案 0 :(得分:9)
将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 接口与用于子类的内部 protected 接口分开。
答案 1 :(得分:6)
这样做的一种方法是定义“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 :(得分:2)
基本上,您的案例是为 Template method design pattern定制的。
答案 3 :(得分:1)
如何使setActive()
非虚拟,而是添加由onSetActive()
调用的第二个虚拟成员(例如setActive()
)?
答案 4 :(得分:1)
我的2美分: 将您的行为分成两个任务:
virtual doActive(){}; //doNothing
void setActive (bool state) {
m_active = state;
doActive();
}