C++ Event System using Delegates

Recently I’ve been working on an Event System in C++. You might be reading that right now and wonder why that small sentence makes it sound like a true endeavor. Well, it was. As many of you may know I’m a student at Champlain College, and in one of my classes, each of the students are tasked to use an event system or a messaging system in their game. The teacher provided us with one, and it’s really great and all, but I couldn’t help but feeling restricted, especially after having used C# for so long where the code is so forgiving, and easy.

I did some research and it turns out that a lot of event systems in C++ are organized in such a way that when you want to do events you must:

  • Create an EventManager class (nothing wrong with this)
  • Create an EventListener class (for setting up events)
  • Create and Event base class
    • Be restricted to use only one function to handle your events
    • Create a huge enum holding a key for each of your events (Can hash it for speed)

I saw those and my heart dropped. I immediately thought that is way to restrictive, there must be an easier way to get events to work. And so the researching began.

My first thought was about delegates (You can think of them as function pointers). I started browsing the Google results and quickly learned that C++ doesn’t have support for delegates (at least is wasn’t anything pretty). I thought well, function pointers? Can’t be too hard to set up. Oh dear, was I wrong. As it turns out, making (*) void function pointers (functions that are not in a class -> not a member function) is really easy and super simple to do. This can be done literally in only a few lines (Delegate constructor omitted).

class Delegate
{
public:
	void Link((*function)(int))
	{
		mFunction = function;
	}
	void Fire(int arg)
	{
		(mFunction)(arg);
	}
private:
	void (*mFunction)(int)
};

What if I wanted to have an event that was linked to a member function? That is a whole other ball game. After hours of scouring the internet, it seemed that my only option (and true savior) was templates. Only recently in our classes have templates been introduced to us, but I know from my previously minor use of them, they ARE very very useful.

Let me break down how to set up a delegate that can link to a member function.

  • Create a template definition that accepts a class parameter (C) for the class that the function is in
  • Create a second template type in that same definition that accepts a function(void (C::*Function)(TypeA*)) in the aforementioned type class
  • Set up a parameter in the function to pass a reference of an instance of class C to the function
  • Store the function and object reference.
  • Create a secondary function that when called will fire the function associated with the object

Sounds easy right? Well, it is when you understand it, it’s much harder when you don’t especially when the “template magic” comes it. Understanding how to use templates with this was the most challenging, yet essential part of create a usable delegate class. I will admit that I did find some very good articles online that helped me a lot though.

class Delegate
{
	typedef void *mInstance; // general instance. Not type specific
	typedef void (*mInternal)(mInstance, EventData*); // Link to internal func
public:
	template <class T, void (T::*Function)(EventData*)>
	void Link(T* obj)
	{
		mInst = obj;
		mInternalFunction = &InternalLaunch<T, Function>;
	}
	void Fire(EventData* arg)
	{
		mInternalFunction(mInst, arg);
	}
	template <class T, void (T::*Function)(EventData*)>
	static inline void InternalLaunch(mInstance ptr, EventData* arg)
	{
		return (static_cast<T*>(ptr)->*Function)(arg);
	}
private:
	mInternal mInternalFunction;
	mInstance mInst;
};

The above sample code only shows how to implement support for JUST member functions. Taking a look at the code you’ll see that it’s essentially just linking to an internal function that launches the templated outside member function. Adding the ability to link to (*)(void) functions is very easy and just requires the simple implementation of a few altered functions. Here is the actual delegate class that I use, and will provide in a download link:

 

class Delegate
{
	//Create some typedefs to manage references easier
	typedef void *InstancePtr;
	typedef void (*InternalFunction)(InstancePtr, EventData*); //This holds an internal function reference

public:

	template <void (*Function)(EventData*)>
	static Delegate* create(void)
	{
		Delegate* del = new Delegate();
		del->Bind<Function>();
        return del;
	}
	template <class C, void (C::*Function)(EventData*)>
	static Delegate* create(C* obj)
	{
		Delegate* del = new Delegate();
		del->Bind<C, Function>(obj);
        return del;
	}

	template <void (*Function)(EventData*)>
	void Bind(void)
	{
		mInst = NULL;
		mInternal = &Method<Function>;
	}
	template <class C, void (C::*Function)(EventData*)>
	void Bind(C* obj)
	{
		mInst = obj;
		mInternal = &ClassMethod<C, Function>;
	}

	void Invoke(EventData* ARG0)
	{
		return mInternal(mInst, ARG0);
	}

	template <void (*Function)(EventData*)>
	static inline void Method(InstancePtr, EventData* ARG0)
	{
		return (Function)(ARG0);
	}
	template <class C, void (C::*Function)(EventData*)>
	static inline void ClassMethod(InstancePtr ptr, EventData* ARG0)
	{
		return (static_cast<C*>(ptr)->*Function)(ARG0);
	}

private:

	Delegate(void) {}

	InternalFunction mInternal;
	InstancePtr mInst;

};

Now using this with an event system is as easy as setting up a map to have references to each of the delegates that have been created. NOTE: You’ll notice that I’ve created two alternate create functions that are static. I’ve done this because I want to be able to create a delegate in one line and then pass that to the EventManager this way I don’t have to create it outside of the event definition.

Get all the files here: Download Event System

If you have any questions feel free to post a comment!

-Tom

2 thoughts on “C++ Event System using Delegates

  1. Hi Tom, that looks very interesting I’m going to have a look through that.
    I’ve been playing around with c++ and directx11 for about 6 months now and have just started to looking into events for my little game I’ve been working on.
    I also came from a c# background and have found what I’ve been reading enjoyable but a real challenge.

    cheers again,
    Dale.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>