纯虚函数是早期绑定(编译时间)还是后期绑定(运行 时间)?

Are pure virtual functions early binding (compile time) or late binding (run time)?

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

但是 pure virtual function 必须在派生的 class 中实现。因此,我不明白为什么在那种情况下需要 vtable。因此我想知道 pure virtual function 是否在运行时或编译时绑定。

如果是在运行时绑定,是否只是针对pure virtual function有一个实现而派生的class调用基础实现的情况?如果没有提供实现会怎样?编译器然后 inline 执行吗?

如您所知,虚函数是在运行时解析的。你需要一个 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() 只会崩溃。

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

设想以下 class 层次结构:

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 函数在 all 派生的 classes 中保持虚拟,这意味着你可以覆盖任何你想要的地方(除非它被声明 final 在某些时候)。编译器无法知道将使用哪个版本。

理论上,如果我们在Base中有virtual void foo() = 0;,在Child中有void foo() final;,编译器会注意到[=18=只有一种可能的实现] 并从 vtable 中优化它,但我从未听说过任何编译器这样做。
这种用例有点违背了纯虚函数的目的。