为什么 std::bind 在使用按引用传递时防止后期绑定?

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

本文关键字:绑定 按引用传递 bind std 为什么      更新时间:2023-10-16

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

#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,即这里发生早期绑定,调用基类的成员函数。

如果我使用指针,即

//...
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); }