4

我正在开发一个包含一些按钮的 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

4 回答 4

3

不要使用指针,boost::functionboost::bind(或std::function如果std::bindC++0x)一起使用,例如

// 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));
于 2011-05-04T19:39:32.257 回答
1

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

于 2011-05-04T19:39:50.270 回答
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();
}

Ideone 上的完整示例。

于 2011-05-04T19:57:09.093 回答
0

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

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

于 2013-12-06T12:23:53.037 回答