C ++通用事件系统

时间:2018-10-30 00:10:57

标签: c++ templates events delegates event-handling

我正在尝试构建通用事件系统。代表和活动应该对彼此一无所知,而经理将处理一切。

考虑到这一点,我创建了一个由函数指针和模板化参数组成的模板化委托/侦听器。

class IDelegate
{
public:
    IDelegate() {};
    virtual ~IDelegate() = 0;
    virtual void exec() = 0;
};

template<class Class, typename... Args>
class Delegate : public IDelegate
{
public:
    typedef (Class::*Function)(Args);
    Delegate(Class* inst, Function func) : instance(inst), function(func) {};
    ~Delegate() { instance = nullptr };

    void exec(Args args)
    {
        instance->function(args);
    }

private:
    Class* instance;
    Function function;
};

我在活动方面做了类似的事情。事件由一个ID和需要传递到函数指针的参数组成。

class IEvent
{
public:
    IEvent() {};
    virtual ~IEvent() = 0;
};

template<typename... Args>
class Event : IEvent
{
public:
    Event(ID eventID, Args args) : id(eventID), arguments(args) {};
    ~Event() = default;

    ID id;
    Args arguments;
};

我选择使用模板,是希望不需要手动创建可能需要的每个事件/委托类。

最后我想做一个单身的经理人。

//EventHandler.h
#pragma once

#include <string>
#include <unordered_map>
#include <queue>

#include "Event.h"

typedef std::string ID;
typedef std::unordered_multimap<ID, void*> Listeners;

class EventHandler
{
public:
    EventHandler(const EventHandler& copy) = delete;
    ~EventHandler();

    EventHandler& operator= (const EventHandler& rhs) = delete;

    void Initialize();
    template<class Class, class TEvent>
    void Run();
    void Shutdown();

    static Listeners::iterator& Register(ID id, IDelegate* listener);
    static void Deregister(Listeners::iterator& iterator);

    static void Post(IEvent* evnt);

private:
    static  Listeners listeners;
    static std::queue<IEvent*> events;
    static EventHandler* instance;

    EventHandler() {};
    EventHandler(const EventHandler& copy);
    EventHandler& operator= (const EventHandler& rhs);
};

//EventHandler.cpp
#include "EventHandler.h"

EventHandler::~EventHandler()
{
    instance = nullptr;
}

void EventHandler::Initialize()
{
    instance = this;
}

void EventHandler::Run()
{
    //TODO: Determine the Event and cast or instantiate to the right class
    IEvent* evnt = events.front; //This should not be IEvent*, but Event<>*
    events.pop();

    listeners[evnt->id].exec(evnt->arguments); //The delegate may need to be casted too.
}

void EventHandler::Shutdown()
{
    instance = nullptr;
}

Listeners::iterator& EventHandler::Register(ID id, IDelegate* listener)
{
    Listeners::iterator iter = listeners.emplace(id, listener);
    return iter;
}

void EventHandler::Deregister(Listeners::iterator& iterator)
{
    listeners.erase(iterator);
}

void EventHandler::Post(IEvent* evnt)
{
    events.emplace(evnt);
}

我遇到麻烦的地方是弄清楚我在Run()中实际使用了什么事件。如果可能的话,我想不用开关或类似的方法就可以避免使用模板化类。我曾经考虑过使函数指针具有相同的签名,因为这样做可以简化一些代码,但会使系统的灵活性降低。

谢谢您的帮助。

0 个答案:

没有答案