将任何类的任何成员函数作为回调函数传递

时间:2011-05-04 19:32:03

标签: c++ callback function-pointers member-function-pointers

我正在开发一个包含一些按钮的OpenGL菜单。我希望能够将一个动作(任何类的成员函数(带有固定签名)!)与按下按钮时执行的按钮相关联。我现在可以做,但只适用于一种类型。我希望能够使用任何类的任何成员函数来进行回调。

现在我这样做:

#define BUTTONCALLBACK(Func) bind1st( mem_fun( &ClassICanSupport::Func ), this )

然后我可以创建一个这样的按钮:

Button* b = new Button("Bla", BUTTONCALLBACK(functionIWanttoCall));

回调函数具有以下签名:

void callback(Button* source);

当我按下按钮时,我可以执行我通过的回调功能。

我看了一下boost :: bind但是我找不到解决问题的方法。此外,我的所有类都派生自一个Object类,所以我想到了一个void *,我可以将它转换为具有一些typeid hack的正确类,但我无法使它工作。最后,我总是遇到这样的问题:我无法完全消除回调函数的类类型(这对于在我的按钮类中保存函数指针是必要的)并且仍然可以调用该函数。

你知道如何解决这个问题吗?

4 个答案:

答案 0 :(得分:3)

不要使用指针,将boost::functionboost::bind一起使用(如果是C ++ 0x,则使用std::functionstd::bind),例如

// in Button class (or whatever signature you need)
Button(const std::string&, boost::function<void(Button*)> callback) // ...
// you can then use callback as a function

// in calling code
Button *b = new Button("..", boost::bind(&Class::func, this));

答案 1 :(得分:1)

您应该使用function<void(Button*)>对象。这些是运行时多态,可以与支持void operator()(Button*)的任何对象一起使用。你可以在Boost,TR1和C ++ 0x中找到一个。 boost::bind适用于这些对象。

答案 2 :(得分:1)

嗯,最简单的方法是使用虚函数,如果你不想引入Boost或者不能访问C ++ 0x。

#include <iostream>

// fwd declare
class Button;

class BtnCallbackBase{
public:
  virtual void operator()(Button*) = 0;
};

template<class C>
class BtnCallback : public BtnCallbackBase{
private:
  typedef void (C::*callback_func)(Button*);

  C* _object;
  callback_func _onclick;

public:
  BtnCallback(C* obj, callback_func func)
    : _object(obj)
    , _onclick(func)
  {}

  virtual void operator()(Button* btn){
    (_object->*_onclick)(btn);
  }
};


class Button{
public:
  Button()
    : _onclick(0)
  {}

  void Click(){
    if(_onclick != 0)
      (*_onclick)(this);
  }

  template<class C>
  void RegisterCallback(C* obj, void (C::*func)(Button*)){
    // cleanup old callback, deleting null pointer is a noop
    delete _onclick;
    _onclick = new BtnCallback<C>(obj,func);
  }

  ~Button(){
    delete _onclick;
  }

private:
  BtnCallbackBase* _onclick;
};

class MyClass{
public:
  void ExampleCallback(Button* btn){
    std::cout << "Callback works!\n";
  }
};

int main(){
  Button btn;
  MyClass test;

  btn.RegisterCallback(&test, &MyClass::ExampleCallback);

  btn.Click();
}

Full example on Ideone.

答案 3 :(得分:0)

如果您想在不使用Boost库的情况下解决问题,而不使用新的C ++功能,那么最好的选择之一是 Danny Kalev / Herb Sutter讨论的 Generic Callbacks Dispatcher 。< /强>

http://www.gotw.ca/gotw/083.htm