3

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 ?

1
  • You need to do additional hacking when passing pointers to C++ methods. See mdzahidh.wordpress.com/2008/07/16/… Commented Jul 13, 2012 at 5:10

5 Answers 5

3

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();
}
Sign up to request clarification or add additional context in comments.

1 Comment

Since you already using c++ then it would be better if each class wont have do_foo method, and make template out of it
1

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

3 Comments

The solution using boost is quite elegant , I would like to know if the above is possible using the std library please.
Then use mem_fun cplusplus.com/reference/std/functional/mem_fun or mem_fun_ptr cplusplus.com/reference/std/functional/mem_fun_ref it might be bit harder but should do the job
@JeffreyChen If your compiler is C++11 capable, see e.g. std::bind and std::function.
1

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.

2 Comments

What should I do if I want to pass a non-static member function of any class ? Is it possible ? If so what do I need to do ? For example in which ever class the button is initiatlized, I want to set its click action to a non-static member function of that class.
@JeffreyChen You cannot create a type capable of holding a member function of any class, but if the classes have a common ancestor, you could store member functions of that ancestor. Of course it would not be necessary in that case, because you would be able to use virtual functions instead of member pointers.
0

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.