c++ - std::bind 是否丢弃 C++11 中参数的类型信息?

标签 c++ c++11 reference polymorphism stdbind

问题发生案例

请考虑以下 C++ 代码:

#include <functional>
#include <iostream>
#include <string>

// Superclass
class A {
    public:
    virtual std::string get() const {
        return "A";
    }
};

// Subclass
class B : public A {
    public:
    virtual std::string get() const {
        return "B";
    }
};

// Simple function that prints the object type
void print(const A &instance) {
    std::cout << "It's " << instance.get() << std::endl;
}

// Class that holds a reference to an instance of A
class State {
    A &instance;
    public:
    State(A &instance) : instance(instance) { }
    void run() {

        // Invokes print on the instance directly
        print(instance);

        // Creates a new function by binding the instance
        // to the first parameter of the print function, 
        // then calls the function. 
        auto func = std::bind(&print, instance);    
        func();
    }    
};

int main() {
    B instance;
    State state(instance);

    state.run();
}

在这个例子中,我们有两个类 ABB 继承自类 A。这两个类都实现了一个返回类型名称的简单虚拟方法。

还有一个简单的方法,print,它接受对A 实例的引用并打印类型。

State 持有对 A 实例的引用。该类还有一个通过两种不同方式调用 print 的简单方法。

奇怪的地方

状态中的唯一方法首先直接调用print。因为我们在 main 方法中提供了 B 的实例,所以输出是 It's B,正如预期的那样。

然而,对于第二次调用,我们使用 std::bind 将实例绑定(bind)到 print 的第一个参数。然后我们在不带任何参数的情况下调用结果函数。

然而,在这种情况下,输出是 It's A。我会像以前一样期待输出 It's B,因为它仍然是同一个实例。

如果我将参数声明为指针而不是引用,std::bind 将按预期工作。我还在两个类的构造函数中放置了一些日志记录,以验证没有意外创建实例。

为什么会这样? std::bind 在这种情况下会丢弃一些类型信息吗?据我了解,这一定不会发生,因为方法调用应该通过运行时的 vtable 查找来管理。

最佳答案

这只是 object slicing .通过引用传递实例:

auto func = std::bind(&print, std::ref(instance));
//                            ^^^^^^^^

再解释一下:与大多数 C++ 标准库类型一样,bind 的结果类型表达式拥有它所有的绑定(bind)状态。这意味着您可以获取此值并自由传递它并存储它并稍后在不同的上下文中返回它,并且您仍然可以调用它并使其所有绑定(bind)状态准备好进行操作。

因此,在您的代码中,绑定(bind)对象是使用 instance拷贝 构建的。 .但是因为 instance不是一个完整的对象,你导致了切片的发生。

相比之下,我的代码复制了一个 std::reference_wrapper<A>进入绑定(bind)对象,这本质上是一个指针。它不拥有实例对象,所以只要绑定(bind)对象可能被调用,我就需要让它保持事件状态,但这意味着绑定(bind)调用以多态方式分派(dispatch)给完整对象。

关于c++ - std::bind 是否丢弃 C++11 中参数的类型信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34366167/

相关文章:

c++ - 为什么在 gcc-4.9.1-4ubuntu2 中没有手动输入 std::vector?

java - Java 中的字符串 : equals vs ==

c++ - std::generate_n 的返回值迭代器,你能用它做什么?

c++ - 给定 bool vector ,如何从 C++ Eigen 数组中删除某些系数?

c++ - 返回不可移动、不可复制的对象时 ctor{} 和 {} 之间的区别

c++ - Google测试-生成用于模板类实例化的值

c++ - 当有人取消引用我的 end() 迭代器时我该怎么办?

java - 在 Java 中将内容从一个对象复制到另一个对象而无需具有相同的对象引用

c++ - 处理 libc++ 和较旧的 libstdc++ 之间的 ABI 差异的好方法是什么?

c++ - 何时在全局范围内使用 new