4

いくつかのボタンを含む OpenGL メニューに取り組んでいます。ボタンが押されたときに実行されるアクション(任意のクラスのメンバー関数(固定シグネチャ付き)!)をボタンに関連付けられるようにしたいと考えています。今すぐできるけど、1種類だけ。コールバックに任意のクラスの任意のメンバー関数を使用できるようにしたいと考えています。

今、私は次のようにしています:

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

次に、次のようなボタンを作成できます。

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

Callback 関数には次のシグネチャがあります。

void callback(Button* source);

ボタンを押すと、渡したコールバック関数を実行できます。

boost::bind を見てみましたが、問題に取り組む方法を実際に見つけることができませんでした。さらに、すべてのクラスはクラス Object から派生しているため、typeid ハックを使用して適切なクラスに変換できる void* について考えましたが、機能させることができませんでした。最後に、コールバック関数のクラスタイプを完全に削除できず(ボタンクラスに関数ポインターを保存するために必要です)、それでも関数を呼び出すことができるという問題が常にありました。

この問題に取り組む方法はありますか?

4

4 に答える 4

3

ポインターを使用しないで、boost::function一緒にboost::bind(またはC++0xstd::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));
于 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 に答える