【问题标题】:Calling overriden (derived class) version of a non-virtual base class function from inside base class?从基类内部调用非虚拟基类函数的重写(派生类)版本?
【发布时间】:2021-05-09 01:04:34
【问题描述】:

所以,如果我有

class base
{
  public:
  virtual void start();
  virtual void stop();

  void doSomething() { start(); .... stop(); }
}

class derived : public base
{
  public:
   void start();
   void stop();
}

调用derived.doSomething() 将调用derived::start() 和derived::stop()。
但这仅在它们是虚拟的情况下才有效。

我想知道为什么没有virtual 关键字就不能工作,这意味着较低级别的细节。我在网上找不到太多关于此的信息...

谢谢!

【问题讨论】:

  • 我可以在虚函数上推荐cppreference.com article
  • 如果没有virtual,它将无法工作,因为virtual 是您告诉基类该函数可能在派生类中被覆盖的方式,从而在运行时确定要调用的版本。因此,这个问题实际上是一个重言式。没有使它起作用的东西,它就不起作用!我相信网上一定有很多关于这方面的资源。

标签: c++ overriding virtual vtable


【解决方案1】:

如果函数被声明为虚拟函数,则该函数的所有覆盖都存储在virtual member function table (vtable) 中。当在您的代码中调用这样的函数时,程序实际上只是指向表的位置。然后使用该表来确定在运行时调用的正确函数。

如果函数未声明为虚拟函数,doSomething 的基类实现中的start()stop() 始终只是指向这些函数的基类定义。

C++ 允许您在两种机制之间进行选择,因为在 vtable 中的运行时查找会产生一些开销,而 C++ 通常不会强加给用户 - “您只需为使用的内容付费”。

wiki 文章的 examplesinvocation 部分很好地展示了技术方面。

【讨论】:

    【解决方案2】:

    如果没有 virtual 关键字,base::doSomething 代码对这些方法的派生版本一无所知(想想链接器解析)

    【讨论】:

    • 这几乎是在挥手。即使使用virtualdoSomething 代码也不知道这些函数的派生版本。 virtual 告诉编译器派生类可能覆盖这些函数,并且作为响应,编译器生成代码以支持覆盖。但如果派生类没有覆盖这些函数,代码仍然有效。 (virtual void start() = 0; 会有所不同,但问题中没有提到。
    • @PeteBecker virtual 关键字告诉链接器通过虚拟表解析调用,在运行时解析。如果它不是虚拟的,链接器会将其解析为静态调用。这就是我所说的 NO IDEA 的意思(静态链接与虚拟表调用,这意味着可能的派生实现的一些想法)。
    • 再说一遍:为基类生成的代码对任何派生类一无所知。它提供了一种机制,派生类可以用来覆盖基类虚函数。
    猜你喜欢
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 2013-08-02
    • 2011-09-27
    相关资源
    最近更新 更多