Reputation: 54133
I'm making a Gui API for games. Basically I have event callbacks in my class which are function pointers. I thought of directly letting the user = the function pointer ex:
widget->OnPaintCallback = myPaintFunc;
But I don't like how I cannot check for NULL or do anything else. It also makes my class feel exposed.
I also thought of having a setter for each callback, but that will get messy in the class (I have over 50)
I then thought of a function that asks for a string indicating which event the handler is for, and its function pointer. But that would evolve needlessly referencing documentation to know the string, and even more confusing for custom undocumented widgets.
Is there a better, cleaner alternative?
Thanks
Could casablankca's solution have multiple arguments?
Upvotes: 1
Views: 1420
Reputation: 70711
But I don't like how I cannot check for NULL or do anything else
How about making the callback (OnPaintCallback
) an object of a class that overloads operator =
, that way you can do any additional checking and throw an exception if something goes wrong. You can also overload operator ()
so that you can call this object as if it were a simple function pointer.
Update: As for variable number of function arguments, there is no general way to do it, but if your maximum N is limited and small, you could use template specializations, for example: (I've omitted constructors, operator =
and other details for clarity)
template<typename T, int N>
class Callback {
};
template<typename T>
class Callback<T, 1> {
T func;
template<typename A1>
void operator ()(A1 arg1) {
func(arg1);
}
};
template<typename T>
class Callback<T, 2> {
T func;
template<typename A1, typename A2>
void operator ()(A1 arg1, A2 arg2) {
func(arg1, arg2);
}
};
I know this is a hacky way to do it but at least your users won't see any of this: they'll get the same interface for all callbacks.
Upvotes: 0
Reputation: 24110
I recommend taking a look at the boost.signals library, or libsigc++. These are very general libaries for managing things like event handlers. They do a lot more than what you are trying to do, but they'll give you ideas for what you may want from your design that you haven't thought of yet.
The more you use your callbacks the more you'll realize that you want more of the features in those libraries (like registering multiple callbacks, binding arguments, being more flexible with types, etc.) So even if you end up doing something simpler, it will be helpful to learn from mature designs.
Upvotes: 1
Reputation: 3746
You can do an interface for each type of event handler you need. Not unlike Java does it. So for example you would have
class PaintCallback {
public:
virtual void paint() = 0;
};
Your event handler would inherit from the abstract class and implement the paint method. In the widget class you would keep a pointer (or a collection) for each handler.
Upvotes: 0
Reputation: 72658
I would suggest the Boost.Signals library. Something like this:
class Widget
{
public:
boost::signal<void (Paint &)> onPaint;
boost::signal<void (MouseMove &)> onMouseMove;
// ... etc
};
// later...
Widget myWidget;
myWidget.onPaint.connect(myPaintFunc);
// and to fire the event:
void Widget::DoPaint()
{
Paint data;
data.whatever = foo;
onPaint(data);
}
This has several advantages:
boost::bind
(or C++0x version of bind
if your compiler supports it) to allow you to bind member functions to event handlers.Upvotes: 1