Search code examples
c++classstructevent-handlingvirtual

Putting virtual functions inside a struct


My goal is to write a system for handling game events which can be triggered by some kind of event occurring such as the player walking killing something or getting an item or what have you. To do this I need to have a virtual function that executes when the event is triggered. Here's the gist of what I want to do (I know that it doesn't work in it's current state but it's the best way I can explain what my goal is):

class EventManager
{
    public:
        typedef struct
        {
            virtual void run();
            bool triggered;
            std::string name;
        } Event;

        void newEvent(std::string eventName)
        {
            Event newEvent;
            newEvent.name = eventName;
            newEvent.triggered = false;
            eventStack.push_back(newEvent);
        }

        void triggerEvent(std::string eventName)
        {
            std::vector<Event>::iterator itr;

            for(itr = eventStack.begin(); itr != eventStack.end(); itr++)
            {
                if(itr->name == eventName) itr->triggered = true;
            }
        }

        std::vector<Event> eventStack;
};

int main()
{
    EventManager* myEventManager = 0;
    myEventManager = new EventManager();

    myEventManager->newEvent("Event1");
    myEventManager->eventStack.back()::run()
    {
        std::cout << "Event1 has been triggered";
    }

    std::vector<EventManager::Event>::iterator itr;

    for(itr = myEventManager->eventStack.begin(); itr != myEventManager->eventStack.end(); itr++)
    {
        if(itr->triggered)
        {
            itr->run();
            itr->triggered = false;
        }
    }

    return 0;
}

So basically my question is, how can I allow the user of my library to define what happens when an event is triggered without having to have them write a class or something for every event?


Solution

  • Consider this: What is really an event? An event (From the point of view of its implementation) is only a list of handlers (callbacks).

    What you called Event is really a class which represents an event handler, and your EventManager is the event itself.

    The solution to your problem is very simple: Use function references (Function pointers, lambdas, functors) to store the set of handlers. For example:

    template<typename... ARGS>
    struct event
    {
       typedef void(*)(ARGS...) handler_type;
    
    
       void add_handler(handler_type handler)
       {
            handlers.push_back(handler);
       }
    
       void raise_event(ARGS args...)
       {
            for(handler_type handler : handlers)
                handler(args...);
       }
    
    private:
        std::vector<handler_type> handlers;
    };
    
    
    void on_foo(int a,int b) { std::cout << "on foo!!! (" << a << "," << b << ")" << std::end; }
    
    
    int main()
    {
        event<int,int> foo;
    
        foo.add_handler(on_foo);
    
        foo.raise_event(0,0);
    }
    

    The implementation above could be optimized using perfect forwarding, but I don't want to overcomplicate the example.