Function pointers to class methods

Started by
7 comments, last by rogierpennink 16 years, 1 month ago
I'm trying to add different camera models to my graphics framework and I'm running into some difficulties with function pointers. I have created a BaseWindow class to which you can add event handlers. The expected function pointer that you have to pass to this function looks like this:
void (*handler)(const Event& e);
So far so good, I can pass global functions as argument and have them handle all kind of events. However, part of the beauty of being able to have multiple event handlers listening for the same event is that any object that needs to be notified on user input can register for receiving those events. This is where I'm getting problems... I have created a base camera class (Camera) which specifies a pure virtual regEventHandlers function, which takes only a BaseWindow object as argument.
virtual void regEventHandlers( BaseWindow* wnd ) = 0;
Derived Camera classes that implement certain camera behaviours (like FPSCamera, or RPGCamera, or anything really) ought to implement this function so they can register for the events that are relevant to their functioning (for example, a flightsim camera would probably want to be notified of joystick events, whereas the mouse is an important event for FPS cameras...). So I tried implementing this for my FPSCamera and ran into the problem that the calling convention of class member functions was different than the calling convention of the expected function pointer in the addEventHandler function. I thought I'd solve this by explicitly setting the calling conventions for the input handling functions in the FPSCamera class to be __cdecl, but this causes an other error. I'll list the implementation of the regEventHandlers function of the FPSCamera class below and also show the error it generates...
/**
 * Function:	regEventHandlers
 * Return:		void
 * Arguments:	A pointer to a BaseWindow object
 * Description:	Registers the appropriate event handlers to receive all necessary 
 *				user input to make this a true FPS camera.
 */
void FPSCamera::regEventHandlers( BaseWindow* wnd )
{
	wnd->addEventHandler( WINDOW_KEYDOWN, &FPSCamera::onKeyDown );
	wnd->addEventHandler( WINDOW_KEYUP, &FPSCamera::onKeyUp );
	wnd->addEventHandler( WINDOW_MOUSEDOWN, &FPSCamera::onMouseDown );
	wnd->addEventHandler( WINDOW_MOUSEUP, &FPSCamera::onMouseUp );
}


These are the errors I get:
cannot convert parameter 2 from 'void (__cdecl FPSCamera::* )(const Event &)' to 'void (__cdecl *)(const Event &)'
Does anyone know a way of doing this or am I really going to have to change my design? Regards, Rogier
Advertisement
Have a read of this.
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
I was afraid it wouldn't be this easy... The question remains though, is there an other way I could have the camera be notified of events gracefully? I should probably mention that I keep my Camera objects in a list in my Renderer and that the renderTarget (which is a BaseWindow) is also kept in my renderer, but you can add Cameras before the renderTarget is initialized so in that case the renderer wouldn't be able to register events for the camera...
Quote:Original post by rogierpennink
I was afraid it wouldn't be this easy... blah blah blah blah


Did you actually read it?


Yes, what did you want to hear? "I've been incredibly stupid for not realising this..." - because that's true, how I could possibly think that passing pointers to member functions of uninstanced classes around would work is still a riddle to me, but we all have our downs.

The problem is, the solution described in the FAQ is to either implement a top-level function or have a global. I find neither solutions very 'elegant'. I suppose the best way compared to that is to have my Renderer register the event handlers for the cameras, but this still has the risk that no renderTarget (BaseWindow) is available at which the event handlers can be registered...
The page then goes on to describe "functioniods" (also know as functors, function objects etc). If you want to implement your own then the information is on that page else you could always use Boost's
Sorry for sounding shirty but you post just sounds like "someone do it for me"
No. What he wanted to hear was... Oh, OK that is pretty easy.

I'll have my camera objects already instantiated so all I need to do is add static functions to my class to wrap the non-static member functions and pass the camera object to my addeventHandler function.

class FPSCamera{public:       void myMemberFunction(int testint)       {	   cout << "this is my member function, the value of the int is: " << testint << endl;       }              static void myStaticMemberFunction(FPSCamera &CameraObject,int testint)       {   	   CameraObject.myMemberFunction(testint);       }};typedef void (*functionptr) (FPSCamera&, int);	  		 int main(int argc, char *argv[]){    FPSCamera myCamera; 	    functionptr theCallback = &FPSCamera::myStaticMemberFunction; 	    theCallback(myCamera,5); 	    system("PAUSE");    return EXIT_SUCCESS;}
This article has some information on writing delegates in C++ that you might find useful.

Personally, when I have to pass pointers to class members around, I use boost::function along with boost::bind, as in this article.

Edit: And this gives some examples of how boost::function + boost::bind can easily give you function objects that you can treat as pointers to class member functions.
Quote:Original post by CmpDev
The page then goes on to describe "functioniods" (also know as functors, function objects etc). If you want to implement your own then the information is on that page else you could always use Boost's
Sorry for sounding shirty but you post just sounds like "someone do it for me"


If I were the kind of person that wanted people to do stuff for me, I wouldn't have started this project in the first place; as it has taken me quite a few sleepless nights to get where I am now. However, i can see why you would think that way as there are a lot of such posts around... So no hard feelings.

Quote:Original post by DeafManNoEars
I'll have my camera objects already instantiated so all I need to do is add static functions to my class to wrap the non-static member functions and pass the camera object to my addeventHandler function.


Thanks for your input! Unfortunately I find a static function to look still very much like a top-level function, so I'll go and play with functors a bit first :)

Regards,

Rogier

Edit:

Thanks for the links to the articles, jcullet. I have not yet worked with boost before; so I'll just take this problem as an opportunity to familiarize myself with it.

This topic is closed to new replies.

Advertisement