构造函数中调用虚方法与绑定后调用为何结果不同?
问题解析:构造函数中绑定虚函数为何最终调用派生类版本
代码片段
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(); }
输出结果
base foo derived foo
疑问点
构造Base期间,对象尚未成为Derived实例,此时调用foo()输出base foo符合预期——因为构造基类时对象的动态类型是Base,虚表指向Base::foo。但构造时通过std::bind绑定了&Base::foo和this指针,为何后续调用p->fn()时会执行Derived::foo?
原因解析
this指针的本质:在Base构造函数中,this的静态类型是Base*,但它实际指向的是Derived对象的基类子对象内存区域。std::bind保存的是这个指针的副本,最终指向的是完整的Derived对象。- 虚函数的调用机制:你绑定的
&Base::foo是一个虚函数的成员指针。对于虚函数,调用时不会直接固定调用基类版本,而是会根据对象的实际动态类型(即构造完成后的Derived类型)去查找虚表中的对应函数。 - 构造前后的动态类型变化:基类构造期间,对象的动态类型是
Base,所以此时直接调用foo()会执行Base::foo;但当整个Derived对象构造完成后,对象的虚表已经切换为Derived的虚表,此时通过std::bind保存的this指针调用虚函数,就会触发Derived::foo的执行。
简单来说,std::bind并没有把调用固定在Base::foo上,只是保存了调用虚函数的入口和对象指针,最终调用哪个版本由对象构造完成后的实际类型决定。
内容的提问来源于stack exchange,提问作者codesavesworld
相关产品推荐
相关产品推荐

