11

我写了一些代码并害怕它不会工作 - 所以我写了一个原型:

#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::...

4

2 回答 2

16

指向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调用部分的this->foo()方式,第二种是跳过virtual方法查找直接调用的方式base::foo

于 2013-04-29T15:40:53.550 回答
1

主要是 action = boost::bind(&base::onDataBaseReady, this, _1); 吓到我了——我们说 &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)();
}

如果调度在绑定时被解决,并且函子被应用于派生类型(你可能不知道确切的类型!),那么派生类型的不变量可能会被破坏。在apply函数的上下文中,不可能知道对象到底是什么,或者该类型的不变量是什么,所以你可能想要做的是让动态调度发挥它的魔力。

[这是从高级设计的角度来看,甚至没有详细说明您不能使用指向成员的指针来执行静态调度......]

于 2013-04-29T17:30:24.730 回答