Моя цель - написать систему для обработки игровых событий, которые могут быть вызваны каким-то событием, например, игрок, который убивает что-то или получает предмет или что у вас есть. Для этого мне нужно иметь виртуальную функцию, которая выполняется при срабатывании события. Здесь суть того, что я хочу сделать (я знаю, что он не работает в этом текущем состоянии, но лучше всего я могу объяснить, какова моя цель):
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;
}
Поэтому в основном мой вопрос: как я могу позволить пользователю моей библиотеки определять, что происходит, когда событие запускается без необходимости писать класс или что-то для каждого события?
Рассмотрите это: что такое событие? Событие (С точки зрения его реализации) - это только список обработчиков (обратных вызовов).
То, что вы назвали Event
, действительно является классом, который представляет обработчик событий, а ваш EventManager
- это событие.
Решение вашей проблемы очень просто: используйте ссылки на функции (указатели функций, lambdas, функторы) для хранения набора обработчиков. Например:
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);
}
Вышеупомянутая реализация может быть оптимизирована с использованием совершенной пересылки, но я не хочу чрезмерно усложнять этот пример.