2013-12-13 3 views
1

У меня мало опыта с общим программированием (мне он редко нужен), но теперь я пытаюсь внедрить систему событий для своего приложения. Это то, что я имел в виду для реальных событий:Присоединение аргументов любого типа к событию

template <typename Arg_Type> struct Event { 
    std::vector<std::string> ids; // All the objects to pass the event to 
    Action action;    // Action to perform (enum) 
    std::vector<Arg_Type> args; // List of event-dependant arguments 
}; 

Но тогда я хотел бы хранить свои различные события в векторе:

std::vector<Event*> events; 

К сожалению, это не кажется, что просто!

Как я могу добиться желаемого эффекта? То есть, возможность передавать события с различными типами аргументов?

Я знаю, что я мог бы сделать что-то вроде этого:

struct Event {}; 

struct EventFloat : public Event {}; 

struct EventString : public Event {}; 

Но это только кажется, безвкусный и труднее поддерживать.

ответ

1

Сделайте свои классы Event<> наследуемыми от общего родителя, скажем EventInterface. EventInterface будет абстрактным классом, который определяет интерфейс ко всем событиям.

class EventInterface 
{ 
    public: 
     virtual void tweak (int t) = 0; 
     virtual void twiddle(int t) = 0; 
     virtual void frob (int f) = 0; 

     virtual ~EventInterface() {}; 
}; 

template <typename Arg_Type> struct Event : public EventInterface { 
}; 

Тогда сделайте свой вектор std::vector<EventInterface *> или тому подобное.

С точки зрения технического обслуживания это не так уж плохо, потому что весь общий класс интерфейса определяет общий интерфейс для всех событий. И если вы действительно хотите добавить новые, не шаблонные классы событий, вы могли бы.

Недостатком является то, что вы не можете сделать ArgType частью общего интерфейса. Однако это имеет определенный смысл: как еще вы могли бы законно вызывать произвольный метод на Event*, если бы не знали типы аргументов?

Теперь вы можете потребовать, чтобы все Arg_Type были подклассами некоторого общего класса EventArgument и определяли ваш интерфейс в терминах этого. Шаблон все равно вас купит. Все зависит от того, как вы хотите определить свой интерфейс событий.

Рабочий пример:

class EventArgument 
{ 
    public: 
     virtual int getId() = 0; 
     virtual ~EventArgument() { }; 
}; 

class EventInterface 
{ 
    public: 
     virtual void tweak (int t) = 0; 
     virtual void twiddle(int t) = 0; 
     virtual void frob (int f) = 0; 
     virtual EventArgument& getArg() = 0; 

     virtual ~EventInterface() {}; 
}; 

class fredArg : public EventArgument 
{ 
    public: 
    virtual int getId() { return 1; } 
    ~fredArg() { }; 
}; 
class barneyArg : public EventArgument 
{ 
    public: 
    virtual int getId() { return 2; } 
    ~barneyArg() { }; 
}; 

template <typename Arg_Type> 
struct Event : public EventInterface 
{ 

    Arg_Type arg; 

    Event() { }; 

    virtual void tweak (int t) { }; 
    virtual void twiddle(int t) { }; 
    virtual void frob (int f) { }; 

    virtual EventArgument& getArg() 
    { 
     return arg; 
    } 
}; 

#include <vector> 
#include <iostream> 

std::vector<EventInterface*> events; 

int main() 
{ 
    events.push_back(new Event<fredArg>()); 
    events.push_back(new Event<barneyArg>()); 

    std::cout << events[0]->getArg().getId() << std::endl; 
    std::cout << events[1]->getArg().getId() << std::endl; 
} 

Печатается 1 и 2, как можно было бы ожидать.

Смежные вопросы