【问题标题】:Why call a Base Class virtual member from an Inherited class?为什么从继承类调用基类虚拟成员?
【发布时间】:2023-04-01 15:58:02
【问题描述】:

我从事 C++ 工作多年,但没有接受过正规培训。我的大部分背景是航空航天,我们必须总是重新发明轮子,不使用 3rd 方库或 API,所以这些对我来说有点新。

我正在开发一些具有 API 的东西,但我对一些现有代码感到有些困惑。问同事时,他们也没有任何答案。

我有一个继承 API 的 Application 类的类。这个Application 类有一个名为onUpdate() 的受保护虚函数,描述为:

更新逻辑的回调函数,每帧调用一次

class MyApp : public Application {
public:
   virtual void onUpdate() override;
}
void MyApp::onUpdate() {
   Application::onUpdate(); // Why do this?
...
}

首先,我认为回调中应该包含某种函数指针 lambda 等。

有人提到的唯一答案是,这是一个“典型”的事情,以便调用可能不同的 Application::onUpdate() 函数。但是如果有基类实现,声明一个虚函数不会覆盖吗?

我原以为如果有必要,文档会说“如果您选择自己编写,请务必调用基类 onUpdate 函数”。

我在通话中尝试了一个断点,它似乎什么也没做。我想知道编译器是否正在优化它,甚至认为我有-O0。我可以删除它,代码看起来运行得很好,但它相当复杂,所以我不想造成一些下游问题。

我什至不确定要搜索什么。我似乎找不到类似的例子。这个实现有正式的名字吗?我无法将我的大脑包裹在这个问题上。

【问题讨论】:

  • 既然您从Application 派生一个新类,大概有一种方法可以让您使用API​​ 注册您的类,以便它知道实际使用它。然后大概在 API 内部的某个地方,通过指向您的类的实例的 Application* 指针对 onUpdate() 进行了调用,从而通过虚拟调度调用了覆盖的 onUpdate()。这是覆盖 onUpdate() 的唯一方法。
  • 大概,这段代码的作者想要保护自己,以防派生类可能需要/受益的某些功能被添加到Application::onUpdate。这是防御性编程的一个例子,尽管在这种情况下可能没有必要。
  • 没有 Application* 指针。派生类有几个函数作为线程产生,这些线程通过 while 循环和 this_thread::sleep() 函数保持活动状态。这一切对我来说都很奇怪。在派生的 onUpdate 函数中的调用堆栈只是说外部代码,所以我假设库代码隐藏了一些东西。
  • 我没有看到任何注册类的调用,而且 API 似乎没有提供任何“注册”功能。我不想这么说,但它只是“神奇地”起作用,这也让我很困扰。
  • @brettgrant99 ApplicationonUpdate 成员函数是纯虚函数吗?如果不是,该函数仍然退出。也许在你的代码执行之前必须先执行某种复杂的初始化代码

标签: c++ inheritance


【解决方案1】:

我认为我提供的信息已经尽可能地回答了最初的问题。

框架的实现决定了它的使用方式。 就我而言,具体的框架隐藏了很多细节。 虽然不常见,但这并非闻所未闻,可以被视为一种反模式,“Call Super”

感谢您的帮助。

【讨论】:

    【解决方案2】:

    为什么要从继承类调用基类虚拟成员?

    如果您希望/需要覆盖函数来完成基本函数的工作,那么调用该函数而不是复制代码会很有用。如果该函数访问基的私有状态,甚至可能是必要的。

    我原以为如果有必要,文档会说“如果您选择编写自己的,请务必调用基类 onUpdate 函数”。

    在必要的情况下,基类文档最好这样说。

    这个实现有正式的名字吗?

    如果您的意思是“此设计模式是否有名称”,则您的问题中没有足够的详细信息来准确回答,但仅根据名称,我猜这是观察者模式的一部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-07
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      相关资源
      最近更新 更多