3

ボタンのクリック関数として任意のクラスの非静的メンバー関数を渡したい場合はどうすればよいですか?出来ますか ?もしそうなら、私は何をする必要がありますか?たとえば、どのクラス(ここではEntityToolGUI)でボタンが開始されたとしても、そのクリックアクションをそのクラスの非静的メンバー関数(クラスEntityToolGUIの非静的メンバー関数)に設定したいと思います。

GUIButton.h

typedef void (*ptr2clickFunc)(void);
class GUIButton : public GUIObject {
  private : void (*clickFunc)(void);
  public : void setClickFunction(ptr2clickFunc clickFunc);
};

GUIButton.cpp
void GUIButton::setClickFunction(ptr2clickFunc clickFunc)
{
  this->clickFunc = clickFunc;
}

EntityToolGUI.h
class EntityToolGUI {
  public : EntityToolGUI();
  protected : void addAnimation();
}

EntityToolGUI.cpp
void EntityToolGUI::addAnimation()
{
  cout<<"add animation"<<endl;
}

EntityToolGUI::EntityToolGUI()
{
  ....
  btnAddAnimation->setClickFunction(&EntityToolGUI::addAnimation);
}

GUIButton :: setClickFunction(void(EntityToolGUI :: *)())への一致する関数呼び出しがないというエラーが発生します

候補はvoidGUIButton:: setClickFunction(void(*)())

これを解決するにはどうすればよいですか?

4

5 に答える 5

3

関数ポインタを渡すほとんどの(まともな)Cコードは、ユーザーコンテキストを関数に渡すために余分なvoid*引数を使用します。これはC++ではそれほど一般的ではありませんが(関数ポインターよりも優れた手法が存在するため)、何らかの理由で関数ポインターの使用に固執している場合は、適切な場合があります。

typedef void (*ptr2clickFunc)(void*);
class GUIButton : public GUIObject {
  private : ptr2clickFunc clickFunc;
  private : void * userdata;
  public : void setClickFunction(ptr2clickFunc clickFunc, void* userdata);
};

class Foo
{
  static void do_foo( void * userdata )
  {
    Foo* thisptr = static_cast<Foo*>(userdata);
    thisptr->foo();
  }
  void foo() { ... }
};

int main()
{
   Foo foo;
   GUIButton button;
   button.setClickFunction( &Foo::do_foo, &foo );
   button.click();
}

編集Bartekが指摘しているように、これを頻繁に行う場合は、静的関数をテンプレートに抽出できます。これは少しこのように見えます(テストされておらず、おそらくマイナーなエラーがあります)。

// GUIButton is as before

// Note no static function here
class Foo { void foo(); }

template<typename T, void(T::*FN)() >
void Call( void * data)
{
  static_cast<T*>(data)->*FN();
}

int main()
{
   Foo f;
   GUIButton button;
   button.setClickFunction( &Call<Foo,&Foo::foo>, &f );
   button.click();
}
于 2012-07-13T06:28:55.927 に答える
1

非静的メンバー関数へのポインターを「通常の」非メンバー関数へのポインターとして渡すことはできません。addAnimation静的にするか、typedefptr2clickFuncメンバー関数へのポインターにする必要があります

メンバー関数へのポインターの呼び出しは、関数ポインターの呼び出しとは異なることに注意してください。これは、メンバーポインターが呼び出されるインスタンスを指定する必要があるためです。

于 2012-07-13T05:12:24.983 に答える
1

obj fun ptrを渡したい場合は、boost::bindとboost::functionを使用できます。

http://www.boost.org/doc/libs/1_50_0/libs/bind/bind.html

于 2012-07-13T05:29:35.813 に答える
0

addAnimationは静的関数である必要があります。コールバック関数が現在のように設定されている場合、クラスEntityTollGUIのオブジェクトは関数とともに登録されません。

于 2012-07-13T05:13:49.927 に答える
0

これを試してください(C ++ 11):

#include <stdio.h>
#include <stdlib.h>
#include <functional>

class Raiser
{
public:
    std::function<void(int)> ev1, ev2;

    void RaiseEv1()
    {
        if (!ev1._Empty())
            ev1(44);
    }

    void RaiseEv2()
    {
        if (!ev2._Empty())
            ev2(66);
    }
};

class Handler
{
private:
    int id;

    std::function<void(int)> h;

public:
    Handler(int newId)
    {
        id = newId;

        h = [this](int i)
        {
            printf("Handler with id = %d captured event!\n", this->GetId());
        };
    }

    void Hook1(Raiser & raiser)
    {
        raiser.ev1 = h;
    }

    void Hook2(Raiser & raiser)
    {
        raiser.ev2 = h;
    }

    int GetId()
    {
        return id;
    }
};

int main(int argc, char * argv[])
{
    Raiser raiser;
    Handler handler1(1), handler2(2);

    handler1.Hook1(raiser);
    handler2.Hook2(raiser);

    raiser.RaiseEv1();
    raiser.RaiseEv2();

    getchar();
}

AFAIK、これは言語拡張機能を使用せずにC++のイベントで取得できる最も多くのものです。

于 2012-07-13T06:05:48.543 に答える