何时在覆盖函数中调用上层次结构的函数?在其他代码之前或之后?

时间:2017-07-30 01:22:46

标签: c++ inheritance virtual

C ++初学者,请耐心等待。

拥有虚拟覆盖功能时,何时应该调用基本功能?应该这样:

void Player::onCollision ( Collidable& otherObject )
{
    /* OTHER CODE */
    /* OTHER CODE */

    PhysicalActor::onCollision ( otherObject );
}

或者这个:

void Player::onCollision ( Collidable& otherObject )
{
    PhysicalActor::onCollision ( otherObject );

    /* OTHER CODE */
    /* OTHER CODE */
}

现在我不知道是否确实存在这样的设定规则 - 是始终先行还是总是最后,甚至是中间。我已经尝试了谷歌搜索,但我不知道该怎么去谷歌,因为标题花了我5分钟的时间来写,我不认为我在任何我读过的书中都记得这个。我总是选择第二个,因为在我的脑海中,你应该首先处理更通用的东西,然后是更具体的东西。

很抱歉,这是一个简单的问题!

谢谢!

1 个答案:

答案 0 :(得分:1)

语言中没有这样的要求。这是一个界面设计问题,虽然库有时需要在特定时间调用基类,但我认为这是一个糟糕的API。

最好的设计不要求用户调用基本版本......永远。这消除了派生类的作者的任何负担。我听说过这个名为无合约的 api设计,因为没有必须接受的协议才能覆盖该功能。

通常情况下,这些合同会让您的用户接受,它会将基类逻辑与客户端覆盖的部分混合在一起。所以而不是:

class Base {
//...   
public:

   // ** this version must be called before an override does anything
   virtual void doSomething() {
      prepare(data); 
   }

private:
   Data data;
}

这要求如果你覆盖doSomething,你必须先做基本版本才能做任何事情。

更好的界面是这样的:

class Base {
//...   
public:
   void doSomething() {  // ** NOT virtual
      prepare(data);
      doSomethingHook();
   }
protected:
   virtual void doSomethingHook() { } // default is to do nothing

private:
   Data data;
}

这保证了任何调用doSomething()的人总是会在调用被覆盖的虚函数之前获得准备好的数据,现在虚拟逻辑被“一点一点地”移动到一个没有排序责任的钩子函数中,只有责任做任何应该做的事情。

当然,doSomethingHook 可能是纯虚拟的,但是一些钩子完全可以留下一个空实现,因为它们的目的是提供选项派生类来定制某些点的行为。