View Full Version : Callbacks to C++ member functions
tentons
01-23-2004, 08:58 AM
I'm banging my head on the floor trying to create a clean way to use callbacks on member functions. Since there must be a this pointer for the callback to work, you have to instantiate the dang function as a class all its own..
But I need to have many objects with a single interface (ie, .update()) to perform arbitrary operations for updating--so each object can have its own update operations but the code just plows through a single list of objects each frame to update everything.
Does anyone have experience with this type of problem? I've seen a few solutions, but they're all pretty messy (maybe I'll have to settle for it).
Is there perhaps another way to achieve the desired effect?
Thanks for any insight!
Roulette
01-23-2004, 09:17 AM
It sounds like what you want is a virtual function.
Create a base class that defines the update() method as a virtual function and then have each of your later classes inherit from that base class and declare their own version of the function. When you obtain a pointer to each class instance and call the update() function, the correct version - which depends on the type of object to which the pointer refers - will be called.
- Roulette
ggambett
01-23-2004, 09:25 AM
Code example :
#define interface struct
#define implements public
interface IUpdate
{
virtual void Update() = 0;
virtual ~IUpdate() {};
};
class AnObject : implements IUpdate
{
public:
AnObject ();
virtual ~AnObject ();
virtual void Update() { printf("Do stuff here\n"); }
};
John Olsen
01-24-2004, 11:24 AM
Look up functors. Here's a good link on setting up non-static C++ member functions for use as callbacks. The general idea is that you need to pass both the class instance and the function somehow when setting up the callback, and this template-based solution is a good approach. It's really tough to pick through if you aren't familiar with templates though.
http://www.tutok.sk/fastgl/callback.html
Pyabo
01-24-2004, 12:56 PM
Functors??? Why would you do that? This is the absolute classic example of exactly when you want to use virtual functions, like Roulette said. Don't make something more complicated than it needs to be.
Rember, K.I.S.S.! :)
Lizardsoft
01-24-2004, 01:40 PM
I agree that it sounds like you want a virtual function, but your post isn't too clear. Just in case you really want C callback functions in a class (for example, to stick a WndProc into a class), the solution I settled on was creating them as static functions. Eg:
static int CMyClass::MyCallBack( HWND hwnd )
{
}
I then manually get the pointer to the object by keeping an index table that maps hwnd to CMyClass * pointers. This assumes that the callback involves passing some parameter that allows you to identify the object. I used hwnd as example because the most common use I find for this involves Win32 callbacks, from which you often get a window handle. So I end up with the first line in the static function being something like
CMyClass *ptrObj = CMyClass::ClassTable( hwnd ); // ClassTable is static member of CMyClass and handles mapping from hwnd->CMyClass *
This is as elegant as I've been able to find for C callbacks, Win32, and classes.
You really sound like you want virtual functions though, not clear where callbacks factor into any of your code...
John Olsen
01-24-2004, 05:45 PM
Depending on how you've set your stuff up, you could do it fairly easily with singletons (classes with a single instance) by saving a static "this" pointer in your constructor, then referencing it from that static callback function. I've used that trick several times to make data storage that's globally visible but still needs to be accessed via the class wrapper.
The difficulty is that it sounds like you want callback-like behavior across several instances, each with their own behavior. If that is the case, then you would definitely want to try subclassing as Roulette mentioned. That gives you one function to call where the behavior can vary based on the instance type, but getting a general function call into that behavior can be tricky.
Still, a good functor library is amazing to behold in the hands of someone who really knows their templates. Compiler support for templates is actually quite good now.
Are you sure you really need callbacks rather than something like a standard tree traversal where derived classes each perform their own custom bits during the traversal?
tentons
01-28-2004, 11:04 AM
Thanks for all the feedback! I really appreciate it.
I looked at functors and also using static member functions, but ended up using a singleton for each type of behavior wrapped in a common (task) interface. My game loop just calls update() for each one, and that's it.
So each task obtains a pointer to the global class instance (upon creation) and jumps there for that particular behavior. This works well, but one caveat is that you have to have some globals for anything that needs to be accessed outside the scope of the class (and also I added a getOwner() function in the task interface to get a pointer to the object the behavior applies to). It's not so bad, though, because things like font objects and so on are generally global anyway.
This was the simplest approach and it also has another benefit of placing the potentially redundant code (in copies of objects) in a single instance which can be shared by any object that wants that behavior.
I've got everything running this way now, from input to rendering to the crude physics. It's pretty sweet, and was worth the trouble.
Thanks again for all the replies! I'll return the favor anytime I can.
ggambett
01-29-2004, 04:43 AM
This works well, but one caveat is that you have to have some globals for anything that needs to be accessed outside the scope of the class (and also I added a getOwner() function in the task interface to get a pointer to the object the behavior applies to). It's not so bad, though, because things like font objects and so on are generally global anyway.
Or have just one global, the instance of a singleton, which holds all your global variables. It's more elegant, and even more if that global represents your application. My code is full of things likeGameApp::getApp()->getTheme()->getDefaultFont() .
tentons
02-01-2004, 04:59 PM
Hmm, true. I probably will end up putting all the global stuff into a class.
Thanks for the suggestion!
Nikster
02-02-2004, 01:50 PM
Globals are evil ;) and singletons are a waste of space imho, you may as well just use a namespace, the best method for this kind of stuff has been mentioned already, and thats having a baseclass with a virtual function, that way, you can have a linked list of all your objects that inherit the base class, and you dont have to worry about class casting (or knowing what it is) to get the function pointer, so you would only have to run through your list calling update, no matter what the actual class is. (of course the list would have to be the base class type tho).
Regards,
N!k