C++ Event Handling?

Started by
4 comments, last by _goat 16 years, 11 months ago
Hi, I did some quick research regarding C++ event-handling and all I found were huge chunks of code with little explanation. It would be nice if someone could explain to me how C++ event handling works? I'm also wondering; do extrernal APIs such as OpenGL have their own event-handling methodologies that are independent of C++'s? Please feel free to go in detail. Thank you.
Advertisement
C++ doesn't have event handling. That's why external APIs all have their own, and it's also why you find tons of code when you search; You have to write your own event handling system from scratch, so there could be lots of code to do that.
C++ has no event handling. (unless you consider exceptions events)

Most common aproach is to use callbacks - a function, that will get called, when something happens.

class MyCallback{  void notify()  {    // do something  }};void perform_operation( MyCallback &cb ){  // do something  // do some more  cb.notify(); // tell we're done}


Obviously, this is rigid and useless. You'd need to hardcode the class, the parameters, the method....

Next, are templates
template < class Callback >void perform_operation( Callback &cb ){  // do something  // do some more  cb.notify();  }


Improvement, you can now use any class as callback, as long as it has a notify() method with no parameters.

Problem still remains, since you might want to change the method name, or use different methods, or not even know the method name during design...

Function pointers - rather than hardcoding a method, just store pointer to it.
template < class ObjectType, class P1 >struct callback1 {	typedef ObjectType & reference;	typedef void (ObjectType::*MethodType)(P1);	callback1( reference instance, MethodType callback  )		: m_instance( instance )		, m_callback( callback )	{}	void operator()( P1 p1 ) const	{		(m_instance.*m_callback)(p1);	}private:	reference m_instance;	MethodType m_callback;};class CallbackHandler{  void notify( int x )  {  }}...// Handler is our true callbackCallbackHandler handler;// Wrap callback function and instance callback1<CallbackHandler, int> int_callback( handler, &CallbackHandler::notify );...template < class Callback >void perform_operation( Callback &cb ){  // do something  // then notify the callback with some value, 15 for example  cb( 15 );}// call the function by specifying our callbackperform_operation( int_callback );


Lots of code....

callback1 is templated wrapper around an object. The whole purpose of that class is to store pointer to an instance of an object, and pointer to method within that object.

callback1 is a specialization of a callback for methods with 1 parameter. For more parameters, you'd have different classes.

Next, callback1 overloads the operator() with 1 parameter to allow the callback to be invoked semantically in the same way as a function.

CallbackHandler is some class, could be any class, which contains callback methods.

int_callback is an instance of a callback that maps between the actual implementation and generic callback handler.


Lastly, after getting a headache from all of this, look into boost::signal, libsigc++, or some other similar library, which does all of the above in a type-safe and thread-safe manner. Also important is that much of the above voodoo is hidden - usage is generally simple and straight-forward, much like declaring methods.

This aproach is somewhat ugly, but will result is extremly efficient code (frequently with no overhead), and retain full type-safety.

Also: there are alternatives to handling events. This is the generic aproach. You can always specialize them without templates, without variable parameters, and similar.
Ok, there are some things I don't understand in the code:

Quote:
template < class ObjectType, class P1 >
struct callback1
{
typedef ObjectType & reference;
typedef void (ObjectType::*MethodType)(P1);


I don't understand what the '&' does in "typedef ObjectType & reference;"
And I have no idea what this is about: "typedef void (ObjectType::*MethodType)(P1);"

could you please explain?

Quote:
callback1( reference instance, MethodType callback )
: m_instance( instance )
, m_callback( callback )
{}


^ I'm not sure what that is, it looks like a constructor, but I don't understand the ": m_instance( instance ), m_callback( callback )" part, it looks like it's extending a superclass, I'm confused.

Quote:
void operator()( P1 p1 ) const {
(m_instance.*m_callback)(p1);
}


Ok, that's really confusing... Why are there two '()' and why is the 'const' just before the '{'?

Ok, Thanks.
You need to look up information on function pointers. That will explain away alot of your confusion.

Your second question is in refrence to an initalizer list, these are fast ways to initalize your variables.
class foo{int a;public: foo() : a(5) { cout << a << endl; } //prints 5}//is faster than if you had used foo() { a = 5; }//and is the only way to do thisclass bar{int &apublic: bar( int &refrenced_var ) : a(refrenced_var) {}}//since refrences have to point to something, you need the initalizer list//to give 'a' a value.


in your third question, the "const" is to tell the compiler that the function has no sideeffect on the current class.
all the () are from the fact that Antheus is using function pointers. And, the
void operator()( P1 p1 )
part has () because it is 'operator()' with '(P1 p1)' as parameters.
As Antheus said, the easiest way is to use Boost.Signals, Boost.Bind and Boost.Function to do all of this dirty work for you:

class Adder{    int i;public:    Adder(int i) : i(i) {}    int add(int a, int b) { return a + b + i; }};int main(){    Adder adder(9);    boost::function< int (int, int) > f = boost::bind(&adder, &Adder::add, _1, _2);    // prints 21    std::cout << f(5, 7) << std::endl;}


Note: It's been a long time since I wrote event code, so I may have made a mistake somewhere up there. It's more than likely.
[ search: google ][ programming: msdn | boost | opengl ][ languages: nihongo ]

This topic is closed to new replies.

Advertisement