You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何传递指针与引用时std::bind表现存在差异?

关于std::bind绑定虚成员函数的行为疑问

需求为获取指向Base::Print的仿函数,以下是测试代码:

#include <functional>
#include <iostream>

using namespace std;
class Base {
 public:
  virtual void Print() {
      cout << "Base" << endl;
  }

  virtual function<void()> get_fx1() {
    return bind(&Base::Print, this);
  }

  virtual function<void()> get_fx2() {
    return bind(&Base::Print, *this);
  }
};

class Derived : public Base {
 public:
  virtual void Print() override {
    std::cout << "Derived" << std::endl;
  }
};

int main()
{
  Derived d;
  Base *ptr = &d;
  ptr->Base::Print();           // 输出Base(符合预期)#out1
  bind(&Base::Print, ptr)();    // 输出Derived(预期为Base)#out2
  ptr->get_fx1()();             // 输出Derived(预期为Base)#out3
  ptr->get_fx2()();             // 输出Base(与out2/out3表现矛盾)#out4

  cout << " -- " << endl;
  Derived d2;
  Base& ref = d2;
  ref.Base::Print();            // 输出Base(符合预期)#out5
  bind(&Base::Print, ref)();    // 输出Base(与out2/out3表现矛盾)#out6

  cout << " -- " << endl;
  (&ref)->Base::Print();        // 输出Base(符合预期)#out7
  bind(&Base::Print, &ref)();   // 输出Derived(与out6表现矛盾)#out8
  
  return 0;
}

原本认为向std::bind传递指针或引用的效果完全相同,但实际表现差异明显:传递指针时绑定&Base::Print,调用后执行的是Derived的重写函数;传递引用时绑定,调用后执行的是Base的原函数。疑问是:std::bind是否会在传递引用时选择性跳过虚表查找?目前未找到相关官方说明。


原因解析

这不是std::bind选择性跳过虚表,而是成员函数指针的调用规则与std::bind的参数值拷贝行为共同作用的结果:

  1. 虚成员函数指针的本质
    &Base::Print是一个虚成员函数指针,即便用类名限定,也不会改变函数的虚属性。调用时是否触发多态,完全取决于调用时的对象类型:
  • 通过指针/引用调用:会触发虚表查找,执行对象实际类型的重写函数;
  • 通过对象值调用:对象会被切片为Base类型,直接执行Base的成员函数。
  1. std::bind的参数处理逻辑
  • 传递指针ptr给bind时,bind会存储指针的副本。调用仿函数时,等价于(ptr->*&Base::Print)()——通过指针调用虚函数,触发多态,因此执行Derived的Print。
  • 传递*this或ref给bind时,bind默认会存储对象的值拷贝。*this在Base成员函数中是Base&,拷贝后成为Base对象;ref是Base&,拷贝后同样是Base对象。调用仿函数时等价于(obj.*&Base::Print)()——通过切片后的Base对象调用,不触发多态,因此执行Base的Print。

验证结论

如果修改get_fx2,用std::ref让bind存储对象引用而非拷贝:

virtual function<void()> get_fx2() {
  return bind(&Base::Print, std::ref(*this));
}

此时调用ptr->get_fx2()()会输出Derived,因为std::ref保留了引用关系,调用时通过引用触发多态。


内容的提问来源于stack exchange,提问作者Samarth S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:34:26