Event System in C++

As a part of getting input into the game I’m working on for the programming course we’re taking right now, I wanted to implement some kind of event system. I come from a background in web development, working a lot with javascript and actionscript and I tend to draw inspiration from there. I always liked the flexibility and ease of use of the event handling in javascript and actionscript, and I wanted to try and do something similar with my system.

Registering an event listener in javascript looks like this:

document.body.addEventListener('click', clickedHandler);

Here, body is an object with the ability to send events to the registered event listeners, 'click' is the event type you want to listen to and clickedHandler is the callback function that is to be called when the event occurs.

A common problem when dealing with javascript events in an object oriented environment is the value of this inside the callback. By default, this refers to the object that dispatched the event, so if you want this to be a specific object, you need a delegate, an anonymous function that when called, calls the desired callback with the desired context:

document.body.addEventListener('click', Delegate(avatar, avatar.jump));

In C++, callbacks can be done easily using function pointers, if you only need to work in the global scope that is. The equivalent of function pointers in an object oriented environment are method pointers, but they are a bit more restrictive as the type of a method pointer does not only include the return type and parameters of the method, but also the type of the containing class. A pointer to a method in a class named Foo with return type void that takes a constant Event reference as it’s single parameter is declared like this:

void (Foo::*method_ptr)(const Event&);

The method can then be called with the object foo of type Foo as it’s context and the event e as input like this:

(foo.*method_ptr)(e);

This means that in order to store such a method pointer for use as a callback, the type of the class that the callback belongs to must be known to the register function. But I need an event system that is flexible enough to register callbacks for several different types. I also need to associate the method with a context object to be able to call it at all (compare this to the js delegate mentioned above). The latter can be achieved by grouping a pointer to a context object and a method pointer in a class:

class EventHandler {

  public:

    EventHandler(Foo* context, void (Foo::*handler)(const Event&)) {

        m_xContext = context;
        m_xHandler = handler;
    }

    void handle(const Event& e) {

        (m_xContext->*m_xHandler)(e);
    }

  private:

    Foo* m_xContext;
    void (Foo::*m_xHandler)(const Event&);
};

A bunch of these handlers can then be registered by an event dispatcher and stored in a vector to be called when a certain object occurs, for example:

Foo foo, bar;

Game::instance()->registerEventHandler(Event::START, foo, &Foo::onStart);
Game::instance()->registerEventHandler(Event::START, bar, &Foo::onStart);

Here, registerEventHandler takes three parameters: an event type to listen to (Event::START), a context object and a method pointer to a method in the Foo class that takes a constant Event reference as it’s only parameter and has the return type void. The event dispatcher (Game::instance() in this case) is responsible for allocating and deallocating the resulting event handlers. This looks a lot like the javascript implementation and is sufficiently easy to use, but it’s still very inflexible as only callbacks from methods in the Foo class can be used. In order to solve this problem, an AbstractEventHandler superclass can be made that is then inherited from by a template EventHandler class:

class AbstractEventHandler {

  public:

    virtual void handle(const Event& e) = 0;
};

template ;
class EventHandler : public AbstractEventHandler {

  public:

    EventHandler(T* context, void (T::*handler)(const Event&)) {

        m_xContext = context;
        m_xHandler = handler;
    }

    void handle(const Event& e) {

        (m_xContext->*m_xHandler)(e);
    }

  private:

    T* m_xContext;
    void (T::*m_xHandler)(const Event&);
};

This enables me to store EventHandlers for several different types in a vector of AbstractEventHandler objects. Registering event handlers now looks like this:

//Code from my PlayerController constructor
Game::instance()->registerEventHandler(
    Event::KEY_DOWN,
    this,
    &PlayerController::keyDownHandler
);
Game::instance()->registerEventHandler(
    Event::KEY_UP,
    this,
    &PlayerController::keyUpHandler
);

While not quite as easy to use as the event listeners in javascript, I feel it’s simple enough, and it’s certainly a flexible approach, allowing me to bind a callback to a specific event for a specific object of any type.

If anyone is reading this who isn’t a spambot, please let me know in the comments if you know of another approach to a flexible event system in C++!