我写了一些代码并且害怕它不起作用 - 所以我写了一个原型:
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
class base {
private:
boost::function<void (int)> action;
protected:
virtual void onDataBaseReady(int i) { std::cout << i << std::endl; }
public:
void call() {
action(10);
}
base() {
action = boost::bind(&base::onDataBaseReady, this, _1);
}
};
class child : public base {
protected:
virtual void onDataBaseReady(int i) { std::cout << i+10 << std::endl; }
};
int main()
{
static child c;
c.call();
std::cin.get();
return 0;
}
编译和工作。 (输出20
)。但为什么?我也在VS2010下进行了测试,并想知道它是否适用于跨平台(比如在GCC下编译)?
主要是action = boost::bind(&base::onDataBaseReady, this, _1);
让我害怕 - 我们说&base::
...
答案 0 :(得分:15)
指向virtual
方法的指针在调用时执行virtual
函数查找。
#include <iostream>
#include <memory>
struct base {
virtual void foo() { std::cout << "base\n"; }
virtual ~base() {}
};
struct derived:base {
void foo() override final { std::cout << "derived\n"; }
};
int main() {
void (base::*mem_ptr)() = &base::foo;
std::unique_ptr<base> d( new derived() );
base* b = d.get();
(b->*mem_ptr)();
}
所以,它“只是有效”。成员函数指针(this->*&base::foo)()
与完全限定的函数调用this->base::foo()
不同。第一种方法是存储调用foo
的{{1}}部分,第二种方法是跳过this->foo()
方法查找并直接调用virtual
。
答案 1 :(得分:1)
主要是action = boost :: bind(&amp; base :: onDataBaseReady,this,_1);吓到我 - 我们说&amp; base :: ...
如果它执行静态调度而不是动态调度,实际上会更加可怕。考虑这个简单的例子:
struct base {
virtual void foo() { /* maintain some invariants */ }
};
struct derived : base {
virtual void foo() { /* maintain different invariants */ }
};
然后考虑在父级绑定函数并在派生对象上调用它。 derived
的实现者知道哪些不变量适用于派生类型,它可能与基类型中的不变量相同,是子集或完全不同。
void apply(base & b) {
std::bind(&base::foo, &b)();
}
如果在绑定时解析了dispatch,并且将仿函数应用于派生类型(您可能不知道确切的类型!)那么派生类型的不变量可能会被破坏。在apply
函数的上下文中,不可能知道对象到底是什么,或者该类型的不变量是什么,所以你可能想做的就是让动态调度发挥其魔力。
[这是从高级设计的角度来看,甚至没有进入细节,你不能使用指向成员的指针来执行静态调度...]