Event class presented here is extremely useful for decoupling your classes from each other. Once you start using this class, all your code will naturally become event-driven. Event-driven programming has the advantage of making code highly expandable, readable and maintainable with no effort or extra lines of code. On the contrary, it allows you to achieve the same results with less code.
I might implement an
event class for Java too. However, the Java version would be a little bit different as without operator overloading support, I would have to define functions like
The class design is based on the observer design pattern.
I will take a top-down approach in explaining how an
event class can be designed. First, the interface we'd expect from a .NET like event is a class that can add/remove handlers and raise an event.
Event& operator += (EventHandler* pHandlerToAdd);
Event& operator -= (EventHandler* pHandlerTorRemove);
Simple enough, but this design asks the user to create a middle object of type
EventHandler. It's better to provide the user with an automatic way with which he ONLY needs to supply his handler function. This is why we'll be adding a class with
static methods that create handlers from the user functions.
static EventHandler* Bind(void(*nonMemberFunctionToCall)());
static methods, now the user can add his functions as handlers without realizing an intermediate object is being created.
myEvent += EventHandler::Bind(myFunc);
Memory-wise, we can opt to use smart pointers or make the
event class own the memory of assigned handlers.
Now what's missing is that the user would want to have a member function as a handler. So, we'll add an overload of
Bind() for that purpose.
static EventHandler* Bind(void(ClassType::*memberFunctionToCall)(), ClassType* instance);
In C++, an instance of the class is needed in order to call a member function, but this is not the biggest of our problems. The big problem is that we can't create a version of
Bind function for each class we intend to use events with, or can we?
Actually we can, and that's by making the new
Bind() function a template function.
template<typename T> static EventHandler* Bind(void(T::*memberFunctionToCall)(), T* instance);
This would seem perfect, but as always, the devil is in the details; The
EventHandler created by
Bind() would need to save the passed pointer, which is of an unknown (
One solution would be to make
template<typename T> class EventHandler
But then operator
Event class won't know what to expect as its argument.
Yes, it is as you've guessed. The trivial solution of using inheritence. So the
event class would keep expecting a pointer to the base
EventHandler class while the
Bind function would create an inherited version.
template<typename T> class EventHandlerImpl: public EventHandler
EventHandlerImpl(void(T::*memberFunctionToCall)(), T* instance);
template<typename T> static EventHandler* Bind(void(T::*memberFunctionToCall)(), T* instance)
return new EventHandlerImpl(memberFunctionToCall, instance);
Finally, to raise the event, some method must be called on that base
EventHandler class. This call has to be virtual as
Bind() would always create us an
EventHandler object of an inherited class.
virtual void RaiseEvent();
operator() of class
Event would call that
virtual function through the pointer it keeps to each handler added.
The final version of the code was tuned a bit and is provided in the attached Event.h file.
Using the Code
When you design your app, you would first decide on your application-level components that perform the business logic. Each of these would have its own separate responsibilities and it would communicate with other components through events.
Shared functionality would be shared through making utility-level classes and injecting them to the application-level components (dependency injection). But this topic is out of the scope of this tip.
#include "Event.h" // This lib consists of only one file, just copy it and include it in your code.
void ProcessPayment(int amount)
void OnMoneyPaid(int& amount);
cashier1.MoneyPaid += Sharp::EventHandler::Bind( &Accountant::OnMoneyPaid, &accountant1);
cashier1.MoneyPaid -= Sharp::EventHandler::Bind( &Accountant::OnMoneyPaid, &accountant1);
- This lib consists of only one file: "Event.h". Just copy it and include it in your code.
- You can define
SHARP_EVENT_NO_BOOST in order to have no dependencies and manage thread-safety at the application level.
Points of Interest
- Event.h is well-documented in the hope that it would help someone out there learn more about templates,
virtual functions and threading in general, as it provides a good example of mixing these technologies.
- A note about the design: In C#, you would need to define a special version of
EventArgs class in order to pass event data. While I understand why the language designers opted to do so, I'm not following the same strategy here and I'm relying on the C++ developer to be wise enough to limit the event class usage to passing actual events only.