functions pointers in classes

Started by
7 comments, last by deadimp 18 years, 10 months ago
I'm having some trouble with these things. See, I'm trying to develop a GUI system, and I need my widgets to have pointers to functions as members, so that they can execute callback functions when an event happens to them. Ok, here's my class definition:

// base class for all GUI objects
class gtGuiWidget
{
protected:
	// callback function pointer//////////
	void (*gtGuiWidget::fpLButtonDownCallback)(void);
	//////////////////////////////////////
	
	// messaging functions ///////////////
	void OnLButtonDown();
	//////////////////////////////////////
	
public:
	gtGuiWidget(void);
	virtual ~gtGuiWidget(void);
};

So whoever is using the gui would write there own callback, and send it to the class. When the widget gets an LButtonDown message, it calls this:

void gtGuiWidget::OnLButtonDown()
{
	(*gtGuiWidget::fpLButtonDownCallback)();
}

This doesn't compile, and I can't figure out the syntax to use. Anyone any ideas?
Advertisement
This is a pointer to a member function, you must call it using:
gtGuiWidget* myWidget;(myWidget->*fpLButtonDownCallback)()
Ah yes, thank you. That works now, although I had to change it to

(*widget->fpLButtonDownCallback)();

Now, is there a way to pass a function pointer as an argument without having to declare all its own arguments, i.e.:

void SetCallBack(void (*func)(void));

The reason is that I want to be able to pass different function pointers to the same function in my widget class, so that I can set up message maps. For example.

widget->SetCallBack(on_l_button_down, L_BUTTON_DOWN);
widget->SetCallBack(on_r_button_down, R_BUTTON_DOWN);
widget->SetCallBack(on_double_click, DOUBLE_CLICK);
etc...

Not all the callbacks would have the same parameter lists.
First pointer to member functions != pointer to free functions

Quote:Original post by JohnHurt
// base class for all GUI objectsclass gtGuiWidget{protected:	// callback function pointer//////////	void (*gtGuiWidget::fpLButtonDownCallback)(void);//...



This is incorrect syntax for pointer to member functions:

struct widget {   // typedef introduces a type alias for another type   // use it to make code clear and concise   typedef void (widget::*button_handler)();    //....private:   button_handler b_hdler;   //....};


Quote:Original post by JohnHurt
That works now, although I had to change it to

(*widget->fpLButtonDownCallback)();


This is incorrect aswell but i'm not surprised as you didn't declare a pointer to a member function in the first place.

The correct syntax is:

pointers :     (ptr->*mem_func_ptr)();references :   (ref.*mem_func_ptr)();


Quote:Original post by JohnHurt
is there a way to pass a function pointer as an argument without having to declare all its own arguments, i.e.:

void SetCallBack(void (*func)(void));

The reason is that I want to be able to pass different function pointers to the same function in my widget class, so that I can set up message maps. For example. Don't nock the simple methods.

widget->SetCallBack(on_l_button_down, L_BUTTON_DOWN);
widget->SetCallBack(on_r_button_down, R_BUTTON_DOWN);
widget->SetCallBack(on_double_click, DOUBLE_CLICK);
etc...


"void (*func)(void)" declares a pointer to function which is not interchangeable with pointer to member functions, they are not equal.

You cannot declare a pointer to free/member function with-out declaring specific arguments, its the signature.

There are many ways to get round that, some of which are:

A. Probably the simplest method is to just have seperate set member function e.g. "setOnButtonDown", setDoubleClick", etc you can always add extra options to each of these. Don't knock simplicity & conciseness.

B. Your method but you have to disregard static typing. This is done by dis-regarding type altogether using the most general pointer type the void pointer (the lowest common dominator of the bunch) and using run-time type switching code or have map that maps key ids to something, when you make a match then you will have to cast the void pointer to the appropriate type. something like so:

enum cb_type { L_BUTTON_DOWN, R_BUTTON_DOWN, DOUBLE_CLICK };void gtGuiWidget::SetCallBack(void* func, cb_type type) {   switch(type) {      case cb_type::L_BUTTON_DOWN:          // ...          break;      case cb_type::R_BUTTON_DOWN:          // ...          break;      case cb_type::DOUBLE_CLICK:          // ...          break;      default:          // ....    }}


You are warned this is horrible coding practice (however using a map would improve things only slightly though) because type switching can be a maintenance nightmare, using void pointers is not type safe, you have no compiler support and whole heap of other nasty-ness.

C. Using templates and advance template techniques, tricks, and idioms but (not being rude here) i think this option maybe currently beyond you.

D. I'm probably missing a whole lot of other options but i'm tired and its getting very late now, i'm sure some one else will add some others.

[Edited by - snk_kid on June 4, 2005 3:04:29 AM]
I think you're misunderstanding what I mean, so I apologise for that.
I don't want a pointer to a member function, I want a member pointer to an external function defined outside the class.

I'm aware of something called Functors, so I'm going to investigate that.
I was reading a little about function objects, or functors, a couple days ago. I think they are objects that act as functions, which doesn't quite sound what you want. They sounded kind of useless to me.
Thanks for your help guys. I found a compromise, which involves passing everything you could ever need to the event handler function of the widget.

I want a system that's kind of like VB, where the developer provides his own callback for the widgets events, i.e.

void btnOK_Click(......)
{
// close app, or whetever
}

It seems to work quite well now!
Quote:Original post by JohnHurt
I think you're misunderstanding what I mean, so I apologise for that.
I don't want a pointer to a member function, I want a member pointer to an external function defined outside the class.


if you just want a pointer to free-function then its simply:

struct gtGuiWidget {   typedef void (*buttonHandler)();   //.....protected:    //.....   buttonHandler fpLButtonDownCallback;   void OnLButtonDown() {      fpLButtonDownCallback();   }   //.....};



Quote:Original post by JohnHurt
I'm aware of something called Functors, so I'm going to investigate that.


A functor is a function with state, a functional object, you can think of it as function + object = functor. To define one in C++ only involves overloading the function call operator for a user-defined type.

This alone probably doesn't buy you much its mostly useful in generic programming using templates, what i think you mean is generalized functions or an instance of the command design pattern.

If you check out the C++ boost library look into boost::function, it allows to define a signature but store any C++ callable entity; a free-function, member function, even other functors including other instances of boost::function that all conform to the signature. So its a functor aswell. Its currently being reviewed to be included in the C++ standard.

May i suggest an alternative for GUI event-handling though, one of the best ways to do this in C++ is by using a signals & slots library (generalized callback framework). There are many signals & slots libraries out there to use, boost also has a signals & slots library.

Quote:Original post by fireside
I was reading a little about function objects, or functors, a couple days ago. I think they are objects that act as functions, which doesn't quite sound what you want. They sounded kind of useless to me.


When you start getting deep into using the C++ standard library generic algoritms they will not be as useless as the first appeared to be.
Going back to your first question, I think your problem was getting mixed up with static members. Using the :: scope operator when calling a member of a class tells the compiler that it is static, when, in fact, it isn't, or at least doesn't seem to be in your code.
void gtGuiWidget::OnLButtonDown(){ //Instead of this: (*gtGuiWidget::fpLButtonDownCallback)(); (*this->fpLButtonDownCallback)(); //Or to get even simpler: (*fpLButtonDownCallback)();}
Projects:> Thacmus - CMS (PHP 5, MySQL)Paused:> dgi> MegaMan X Crossfire

This topic is closed to new replies.

Advertisement