简体   繁体   中英

Passing a function pointer to a function

What should I do if I want to pass a non-static member function of any class as a click function of the button ? Is it possible ? If so what do I need to do ? For example in which ever class (EntityToolGUI over here) the button is initiatlized, I want to set its click action to a non-static member function (a non-static member function of class EntityToolGUI ) of that class.

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);
}

I am getting an error no matching function call to GUIButton::setClickFunction(void (EntityToolGUI::*)())

candidate is void GUIButton::setClickFunction(void (*)())

How do I solve this ?

Most (decent) C code that passes function pointers around use an extra void* argument for passing user context to the function. This is not so common in C++ (as better techniques than function pointers exist), but if you're stuck using function pointers for some reason then it may be appropriate.

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();
}

EDIT As noted by Bartek, if you're doing this a lot you can extract the static function into a template - it looks a bit like this (untested and probably with minor errrors).

// 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();
}

You cannot pass a pointer to non-static member function as a pointer to a "regular" non-member function. You should either make addAnimation static, or make ptr2clickFunc typedef a pointer to member function .

Note that invoking a pointer to member function is different from invoking a function pointer, because you must supply an instance on which the member pointer is to be invoked.

If you want to pass obj fun ptr you can use boost::bind and boost::function

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

addAnimation needs to be static function. When the call back function is set the way you are doing it now, the object of class EntityTollGUI is not registered along with the function.

Try this one (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, this is the most you can get with events in C++ without using language extensions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM