什么时候调用override函数中的上层函数?在其他代码之前还是之后?

Posted

技术标签:

【中文标题】什么时候调用override函数中的上层函数?在其他代码之前还是之后?【英文标题】:When to call the upper hierarchy's function in overriden function? Before or after other code? 【发布时间】:2017-07-30 01:22:46 【问题描述】:

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】:

语言中没有这样的要求。这是一个接口设计问题,虽然库有时确实需要在某些时候调用基类,但我认为这是一个糟糕的 API。

最好的设计不需要用户调用基本版本......永远。这消除了派生类的作者的任何负担。我听说过这种称为 contract-free 的 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 可能是纯虚拟的,但有些钩子可以留空实现,因为它们的目的是提供 选项派生类来自定义特定点的行为。

【讨论】:

非常感谢这个答案和我从未想过的解决方法。我很可能会在某个时候使用它。 +1

以上是关于什么时候调用override函数中的上层函数?在其他代码之前还是之后?的主要内容,如果未能解决你的问题,请参考以下文章

重载(overload)覆盖(override)隐藏(hide)的区别

回调函数究竟有啥使用价值,有否例子,效率如何

覆写(Override)和重载(Overload)的比较

避免在构造函数中调用虚方法(Do not call overridable methods in constructors)

抽象类,抽象函数

同步回调函数和异步回调函数