【问题标题】:C++: Virtual functions that need to call the same code?C++:需要调用相同代码的虚函数?
【发布时间】:2012-02-06 06:21:09
【问题描述】:

我有一个基类和派生自它的类。基类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 切换到正确状态的预期效果的最佳方法是什么,同时不需要派生类除非他们需要附加额外需要的代码,否则定义它?

【问题讨论】:

  • 你在}函数之后有;,注意它们。
  • Mr.TAMER - 已修复!我很痒;手指

标签: c++ inheritance c++11


【解决方案1】:

保持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 接口分开。

【讨论】:

  • 谢谢!我没有想到以这种方式使用非虚拟方法。我还有许多其他基类可以从这种处理中受益。
  • activeChanged 应该是私有的,而不是受保护的,因为派生类永远不需要调用基类的实现,只需覆盖它。
  • 次要“错误”:尽管名称不改变状态,但您仍会调用 activeChanged()(例如 m_active 评估为 true,然后您再次调用 setActive(true))。
【解决方案2】:

一种方法是定义“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() 方法在此技术中不是虚拟的。

【讨论】:

  • 太酷了。在这种情况下,之前和之后有两个函数可能有点过头了,但我还有一些其他类非常适合。谢谢!
【解决方案3】:

基本上,您的案例是为 Template method design pattern 定制的。

【讨论】:

    【解决方案4】:

    如何将setActive() 设为非虚拟,而是添加由setActive() 调用的第二个虚拟成员(例如onSetActive())?

    【讨论】:

      【解决方案5】:

      我的 2 美分: 将你的行为分为 2 个任务:

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

      【讨论】:

        猜你喜欢
        • 2016-02-05
        • 2012-07-06
        • 2016-01-01
        • 2013-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-29
        相关资源
        最近更新 更多