Hello List,

I'm creating a Button where I want to add a function setActionOnReleased(func aFunction);

From any class I'd like to instantiate this Button class and send it the function I want to execute.

I found some reference to using member function pointers ( http://bytes.com/topic/c/answers/569262-passing-function-argument ),
but I'd like to send the function pointer to another class ( Button ).

--Button.h:

class Button{
	
public:
	typedef void (Button::*func)();
	
	func onUp;
	Button();
	void setActionOnReleased(func onReleasedFunction);
	void mouseReleased(ofMouseEventArgs & mouse);
};

--Button.cpp:

#include "Button.h"


Button::Button(){

}

void Button::setActionOnReleased(func onReleasedFunction){
	onUp=onReleasedFunction;
}

void Button::mouseReleased(ofMouseEventArgs & mouse){
	printf("mouse released");
	(ouUp)();
}

and from any class I'd like to call:

void SettingsButton::connect(){
		printf("connecting...");
}
button=new Button();
button->setActionOnReleased(&connect);

I think that what you need is passing a function as argument. In order to do this you may need to have a pointer to the function you want to be an argument. In c++ this can be done like this:

int f(int);    //Declaring the function
int (*pf)(int) //Declaring a function pointer
pf = &f;       //Assign the address of f to pf
pf (4);        //Callinf pf which is f

When passing functions as arguments you need to specify it on the () of the function receiving
Example:

void f(int x){
   return x*2;
}
void fcaller(int (*pf)(int)){
    ...
    j = pf(4);
    ...
}
void main(){
    fcaller(f);
}

Ok, let me explain better...

I have a class Button, and from another class I want to instatiate Button and send it a function that will be called by Button::mouseReleased.

void AClass::connect(){
		printf("connecting...");
}
button=new Button();
button->setActionOnReleased(&connect);

My difficulty is in sending the AClass::connect() function to be stored in Button:

void Button::setActionOnReleased(func onReleasedFunction){
	onUp=onReleasedFunction;
}

and later be called from Button:

void Button::mouseReleased(ofMouseEventArgs & mouse){
	printf("mouse released");
	(ouUp)();
}

please tell me if I managed to make it clear....

thanks

Tried Huakalero idea:

added as comments the error I get!

--Button.h:

class Button{
 
public:
	void (onUp)();
 
	Button();
	void setActionOnReleased( void (*onReleasedFunction)() );
	void mouseReleased(ofMouseEventArgs & mouse);
};

--Button.cpp:

#include "Button.h"
 
 
Button::Button(){
 
}
 
void Button::setActionOnReleased(void (*onReleasedFunction)() ){
	onUp=&onReleasedFunction; // invalid use of member
}
 
void Button::mouseReleased(ofMouseEventArgs & mouse){
	printf("mouse released");
	ouUp();
}

then:

void AClass::connect(){
		printf("connecting...");
}
button=new Button();
button->setActionOnReleased(connect); //error: no matching function for call to 'Button::setActionOnReleased(<unresolved overloaded function type>)'

Edited 6 Years Ago by 344server: n/a

Notice that the class should have a pointer to a function like this:

void (*onUp)(); //Declaring a function pointer

There's no * in your code, so you are just declaring a function not a pointer to a function

Also, when you call the setAction you are not referring to the function of Aclass since you are just using:

setAction(connect);

//and it should be something like:

setAction(Aclass.connect);

Edited 6 Years Ago by Huakalero: adding info

ops! Thanks so much for helping!
I guess I'm almost there...

Now I only get the error argument of type 'void (AClass:: )()' does not match 'void (*)()'

I tried declaring connect as a 'normal' function, but get the error 'connect' was not declared in this scope

... in AClass:

connectButton->setActionOnReleased( connect );
}

void connect(){
        printf("connecting...");
}

Edited 3 Years Ago by happygeek: fixed formatting

In this case, there are several options available to you. Here are two that I would recommend (btw, these are examples you can compile and run):

1) Polymorphism: This is a basic object-oriented implementation for this problem using an interface class for all class that could implement a response for your mouse release event. It goes as follows:

#include <cstdio>

//define an interface class for all the responder classes 
class ReleaseResponder {
  public:
    virtual void OnRelease() = 0; //with a pure virtual response function (callback).
};

//hold a pointer to that interface class in the Button class:
class Button {
  private:
    ReleaseResponder* responder;
  public:
    Button() : responder(NULL) { };
    void setActionOnReleased(ReleaseResponder* aResponder ) { 
      responder = aResponder;
    };
    void mouseReleased() {
      printf("mouse released");
      if(responder)
        responder->OnRelease();
    };
};

//Make whatever class you want to use as responder implement the responder interface:
class AClass : public ReleaseResponder {
  public:
    //....
    void OnRelease() {
      printf("responding...");
    };
};

//then you set it up as:
int main() {
  AClass* myResponder = new AClass();
  Button* myButton = new Button();
  myButton->setActionOnReleased(myResponder);
  //test it:
  myButton->mouseReleased();
  return 0;
};

2) Generic Programming: Now this is more advanced and is a basic form of template meta-programming. You will probably not choose this because of the additional complexity, but it is far more flexible as the example demonstrates. The idea is to use a template policy class to implement the mouse release response (as a callable policy):

#include <cstdio>

//define a default policy class for all the responder policies 
struct NoRespondPolicy {
  void operator()() {
    printf("not responding...\n");
  };
};

//make the Button class templated with the responding policy:
template<class OnRelease = NoRespondPolicy>
class Button {
  private:
    OnRelease responder; //hold release responder object (will be a function pointer or other type)
  public:
    Button() { };
    Button(OnRelease aResponder) : responder(aResponder) { };
    void setActionOnReleased(OnRelease aResponder ) { 
      responder = aResponder;
    };
    void mouseReleased() {
      printf("mouse released\n");
      responder(); //Call the responder for the released event.
    };
};

//create a special policy for pointer to member functions:
template<class T>
class MemberFuncRespond {
  public:
    typedef void (T::*VoidFuncPtr)();
  private:
    T* Obj; //hold the object pointer.
    VoidFuncPtr Func; //hold the member function pointer.
  public:
    MemberFuncRespond(T* aObj, VoidFuncPtr aFunc) : Obj(aObj), Func(aFunc) { };
    void operator() () {
      if(Obj)
        (Obj->*Func)(); //call the member function pointer on the object Obj.
    };
};

//Make whatever class you want to use as respond:
class AClass {
  public:
    //....
    void OnRelease() {
      printf("responding with on release function...\n");
    };
    typedef void (AClass::*VoidFunc)(); //useful typdef
    typedef MemberFuncRespond<AClass> Responder; //another useful typedef
    //create a responder object for any void member function pointer.
    Responder getResponder(VoidFunc FPtr) { return Responder(this,FPtr); };

    void operator()() {
      printf("responding with operator ()...\n");
    };
};

void GlobalOnRelease() {
  printf("responding with global function...\n");
};

//then you set it up as:
int main() {
  AClass myResponder;

  Button<> myButton1; //no response (default policy)  
  myButton1.mouseReleased();

  Button<AClass&> myButton2(myResponder); //respond with AClass.operator()
  myButton2.mouseReleased();

  Button< AClass::Responder > myButton3(myResponder.getResponder(&AClass::OnRelease)); //respond with AClass.OnRelease()
  myButton3.mouseReleased();

  Button<void (*)()> myButton4(&GlobalOnRelease); //respond with GlobalOnRelease()
  myButton4.mouseReleased();

  return 0;
};

Thanks for the help Mike,

Your post was very elucidating and I managed to solve the issue. I used your first approach, but shore will try the second. :D

This article has been dead for over six months. Start a new discussion instead.