为什么 std::bind 使用引用传递时会阻止后期绑定?

Why does std::bind prevent late binding when using pass-by-reference?

我有一个基 class、一个派生 class 和一个虚拟成员函数。我还有一个函数,它接受一个基 class 引用并对成员函数进行多态调用:

#include <iostream>
#include <functional>
class Base
{
public:
    Base() {}
    virtual int getnum() { return 1; }
};

class Derived : public Base
{
public:
    Derived() {}
    virtual int getnum() { return 2; }
};

int getnumref(Base& b) { return b.getnum(); }

int main()
{
    Derived d;
    Base& bref = d;
    std::cout << getnumref(bref) << std::endl;
}

这里发生了后期绑定,输出为2.

但是如果我现在将以下行添加到 main() 函数中以便预先定义函数的参数,然后调用它:

std::function<int()> boundgetnumref = std::bind(getnumref, bref);
std::cout << boundgetnumref() << std::endl;

那么最后一行的输出是1,即这里发生了早期绑定,调用了基class的成员函数

如果我使用指针,即

//...
int getnumptr(Base* b) { return b->getnum(); }
//...
int main()
{
    Derived d;
    Base* bptr = &d;
    std::cout << getnumptr(bptr) << std::endl;
    std::function<int()> boundgetnumptr = std::bind(getnumptr, bptr);
    std::cout << boundgetnumptr() << std::endl;
}

那么两个 cout 调用的输出都是 2.

为什么当我将引用传递与 std::bind 一起使用时会发生早期绑定,而不是其他情况?

std::bind 按值存储捕获的参数,导致 Derived 的切片副本到 Base

如果你只是传递 std::reference_wrapper(一个指针)来复制指针,那么切片复制就不会发生:

std::function<int()> boundgetnumref = std::bind(getnumref, std::ref(bref));

尽管更喜欢 lambda,它们是最佳实践:更易于编写、阅读且更高效:

auto boundgetnumref = [&bref]() { return getnumref(breg); }