【问题标题】:Are pure virtual functions early binding (compile time) or late binding (run time)?纯虚函数是早期绑定(编译时)还是后期绑定(运行时)?
【发布时间】:2019-08-14 23:13:48
【问题描述】:

我在各种在线资源中看到 virtual functions 是运行时绑定的。

但是,pure virtual function 必须在派生类中实现。所以,在那种情况下为什么需要vtable 对我来说没有意义。因此,我想知道 pure virtual function 是否在运行时或编译时绑定。

如果在运行时绑定,是不是只针对pure virtual function有实现,派生类调用基实现的情况?如果没有提供实现会发生什么?那么编译器会inline 实现吗?

【问题讨论】:

标签: c++ virtual-functions vtable pure-virtual


【解决方案1】:

正如您已经发现的,虚函数是在运行时解析的。对于这种情况,您需要一个 vtable:

class Parent {
 public:
  virtual void pure() = 0;
};

class Child : public Parent {
 public:
  void pure() {}
};

void do_pure(Parent& x){
   x.pure();
}

int main(){
  do_pure(Child());
}

Child() 实例在传递给do_pure 时被转换为Parent。然后,x.pure() 行需要 vtable 才能定位 pure() 的实现的内存地址。

如果Child 不实现do_pure,则无法编译,因为x.pure() 行只能崩溃。

【讨论】:

  • 因此,如果您没有对父级进行任何强制转换,而只是在 main 中调用 Child().pure(),那么编译器是否足够聪明,可以简单地取消 vtable?
  • @TerenceChow vtable 仍将存在于(临时)Child() 对象中,但可以在不使用 vtable 的情况下对 pure 进行函数调用,因为完整的对象类型是已知的。
  • Godbold 说是的:godbolt.org/z/DVr546。整个临时对象都被优化掉了。
  • 多亏了final,去虚拟化越来越受到关注,所以说它们在运行时完全停止并不完全准确。
  • vtable 不在对象中。指向的指针在对象中。
【解决方案2】:

所有virtual 函数都需要后期绑定。

想象以下类层次结构:

struct Base {
    virtual void foo() = 0;
    virtual ~Base() = default;
};

struct Child: public Base {
    void foo() override { std::cout << "I'm good!"; }
};

struct Grandchild: public Child {
    void foo() final { std::cout << "But I'm better!"; }
};

void fooCaller(const Base& b) {
    //Which foo() do I call here? Child::foo() or Grandchild::foo()?
    b.foo();
}

int main() {
    Grandchild g;
    fooCaller(g);
}

virtual 函数在 所有 派生类中保持虚拟,这意味着您可以在任何您想要的地方覆盖(除非它在某个时候被声明为 final)。编译器无法知道将使用哪个版本。

理论上,如果我们在Base 中有virtual void foo() = 0;,在Child 中有void foo() final;,编译器会注意到foo 只有一种可能的实现,并在vtable 之外对其进行优化,但我从来没有听说有任何编译器这样做。
而且这样的用例有点违背纯虚函数的目的。

【讨论】:

  • 不能在基类中标记为final,因为没有纯final虚函数。因此,从基类继承的类可以覆盖它。
  • @Chronial 这可能很奇怪,但标准并不禁止纯虚最终函数(参见cppreference 中的语法#1)。我的意思是,提供纯虚函数实现的第一个类(可能是Child),也将其标记为final,我将尝试进一步澄清。
  • 得益于final,去虚拟化正在获得关注,因此说它们是“全部”后期绑定并不完全准确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
  • 1970-01-01
  • 1970-01-01
  • 2021-10-23
  • 1970-01-01
  • 2012-05-22
相关资源
最近更新 更多