Emi*_*elt 4 c++ polymorphism reference stdbind c++11
出现问题的情况
请考虑以下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();
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我们有两个类A和B.B继承自班级A.这两个类都实现了一个返回类型名称的简单虚方法.
还有一个简单的方法,print它接受对实例的引用A并打印该类型.
该类State包含对实例的引用A.该类还有一个简单的方法,可以print通过两种不同的方式调用.
奇怪的地方
状态中唯一的方法是print直接调用.由于我们B在main方法中提供了int 实例,因此输出It's B正如预期的那样.
但是,对于第二个调用,我们将实例绑定到printusing 的第一个参数std::bind.然后我们调用结果函数而不带任何参数.
但是,在这种情况下,输出是It's A.我会It's B像以前一样期望输出,因为它仍然是同一个实例.
如果我将参数声明为指针而不是引用,std::bind则按预期工作.我还在两个类的构造函数中放置了一些日志记录,以验证是否没有意外创建实例.
为什么会这样?std::bind在这种情况下会丢弃某些类型的信息吗?根据我的理解,这不应该发生,因为方法调用应该通过运行时的vtable查找来管理.
这只是对象切片.通过引用传递实例:
auto func = std::bind(&print, std::ref(instance));
// ^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
为了解释这一点:与大多数C++标准库类型一样,bind表达式的结果类型拥有其所有绑定状态.这意味着您可以获取此值并自由传递并存储它,稍后在不同的上下文中返回它,您仍然可以在其所有绑定状态准备好进行操作时调用它.
因此,在您的代码中,绑定对象是使用的副本构造的instance.但由于instance不是一个完整的对象,你导致切片发生.
相比之下,我的代码将a复制std::reference_wrapper<A>到绑定对象中,而这实际上是一个指针.它不拥有实例对象,因此只要可以调用绑定对象,我就需要保持活动状态,但这意味着绑定调用将以多态方式分派给整个对象.