为什么在构造函数中调用虚拟方法并绑定虚拟方法然后稍后调用它会产生不同的结果?

zxy*_*122 7 c++ constructor virtual-functions stdbind

这是我的代码片段:

class Base {
  public:

  Base() {
    foo();
    bind();
  }

  virtual void foo() {
    std::cout << "base foo\n";
  }

  void bind() {
    fn = std::bind(&Base::foo, this);
  };

  std::function<void()> fn;
};

class Derived : public Base {
  public:

  void foo() override {
    std::cout << "derived foo\n";
  }

  void bind()  {
  }

  int val;    
};

int main() {
  Base* p = new Derived();
  p->fn();
}
Run Code Online (Sandbox Code Playgroud)

输出是:

class Base {
  public:

  Base() {
    foo();
    bind();
  }

  virtual void foo() {
    std::cout << "base foo\n";
  }

  void bind() {
    fn = std::bind(&Base::foo, this);
  };

  std::function<void()> fn;
};

class Derived : public Base {
  public:

  void foo() override {
    std::cout << "derived foo\n";
  }

  void bind()  {
  }

  int val;    
};

int main() {
  Base* p = new Derived();
  p->fn();
}
Run Code Online (Sandbox Code Playgroud)

foo()打印,因为根据此问题base foo下的答案,此时 vtable 仍然指向。Base::foo

在 的构造过程中Base,该对象还不是Derived类。那么,调用时std::bind()指针this仍然是类的指针Base,而实参指针是在构造函数体内传递的Base,那么为什么要在类中p->fn调用呢?fooDerived

我的编译器是Apple clang版本14.0.3

Ben*_*igt 6

std::bind(或任何其他使用指向成员函数的指针,其中所讨论的成员函数是virtual)不绑定到特定函数。相反,当与虚拟成员函数一起使用时,它绑定到虚拟调度槽1(即使用 vtable 的常见实现上的 vtable 槽)。

所以当vtable被更多的派生构造函数重新配置后,通过结果函子找到的函数就会bind发生变化。


1导致成员函数指针类型过大的原因有很多,其中不仅仅包含代码地址,而且能够虚拟分派的需求就是其中之一。


Dre*_*ann 3

当调用std::bind时仍然是一个指向Base类的指针,并且参数指针是在Base的构造函数体内传递的,为什么p->fn在派生类中调用foo?

一旦Derived调用构造函数,每个指向 的指针现在Base都是指向 的指针Derived。从该位置访问的 vtable 现在是派生 vtable

这就是动态调度的“动态”部分。