So here is what I have. To me, it still seems like a strange way of doing it, as it seems template heavy, but it has performed well in my tests and is pretty easy to use. I would appreciate any suggestions, criticisms, improvements, other designs, etc.
Event classes:
// Description: All events derive from this base class. This can be used to
// store events of different types together.
//
// Inheritance: None
//
// Example Usage:
// std::vector<EventBase*> events;
// events.push_back(new KeyDownEvent());
// events.push_back(new KeyUpEvent());
class EventBase {
public:
// ctors/dtor: =============================================================
EventBase() : handled_(false) {}
virtual ~EventBase() {}
// public functions: =======================================================
void SetHandled(bool handled) { handled_ = handled; }
bool IsHandled() const { return handled_; }
protected:
// protected static functions: =============================================
static unsigned int GenerateUniqueID();
private:
// vars: ===================================================================
bool handled_;
};
unsigned int EventBase::GenerateUniqueID() {
static unsigned int id = 0;
++id;
return id;
}
// Description: Generates a unique integer ID for an event that derives from
// this class. All concrete events should derive from this class.
//
// Inheritance: EventBase -> Event<EventT>
//
// Example Usage:
// class SomeEvent : public Event<SomeEvent> {
// public:
// SomeEvent(int data) : data_(data) {}
//
// void SetData(int data) { data_ = data; }
// int GetData() const { return data_; }
//
// private:
// int data_;
// };
template<typename EventT>
class Event : public EventBase {
public:
// public static constants: ================================================
static const unsigned int kID;
};
template<typename EventT>
const unsigned int Event<EventT>::kID = Event<EventT>::GenerateUniqueID();
Listener classes:
// Description: All event listeners derive from this base class. This can be
// used to store listeners of different types together.
//
// Inheritance: None
//
// Example Usage:
// std::vector<EventListenerBase_Interface*> listeners;
// listeners.push_back(new KeyDownListener());
// listeners.push_back(new KeyUpListener());
class EventListenerBase_Interface {
public:
// ctors/dtor: =============================================================
virtual ~EventListenerBase_Interface() {}
};
// Description: Generates a unique OnEvent method for each event input for
// EventT. All event listeners should derived from this class.
//
// Inheritance: EventListenerBase_Interface -> EventListener_Interface<EventT>
//
// Example Usage:
// class SomeEventListener
// : public EventListener_Interface<KeyDownEvent>,
// public EventListener_Interface<KeyUpEvent> {
// public:
// SomeEventListener() {}
//
// void OnEvent(KeyDownEvent* event) {
// // do something
// }
//
// void OnEvent(KeyUpEvent* event) {
// // do something
// }
// };
template<typename EventT>
class EventListener_Interface : public EventListenerBase_Interface {
public:
// dtors: ==================================================================
virtual ~EventListener_Interface() {}
// public functions: =======================================================
virtual void OnEvent(EventT* event) = 0;
};
EventDispatcher:
// Description: Used to register events listeners and dispatch events.
//
// Inheritance: None
//
// Example Usage:
// EventDispatcher dispatcher;
// SomeListener listener;
//
// dispatcher.Register<SomeEvent>(SomeEvent::kID, &listener);
// dispatcher.Dispatch(SomeEvent::kID, new SomeEvent());
class EventDispatcher {
public:
// typedefs: ===============================================================
typedef std::vector<EventListenerBase_Interface*> ListenerVector;
typedef std::map<int, ListenerVector> ListenerMap;
// ctors/dtor: =============================================================
EventDispatcher() {}
// public functions: =======================================================
// - dispatch event
template<typename EventT>
void Dispatch(int type, EventT* event);
// - register listeners
template<typename EventT>
void Register(int type, EventListener_Interface<EventT>* listener);
private:
// vars: ===================================================================
ListenerMap listeners_;
};
template<typename EventT>
void EventDispatcher::Dispatch(int type, EventT* event) {
if (event == NULL) { return; } // disallow a NULL event
ListenerMap::iterator itr = listeners_.find(type);
if (itr == listeners_.end()) { return; } // event type not found
// dispatch event to the listeners
for (unsigned int x = 0; x < itr->second.size(); ++x) {
static_cast<EventListener_Interface<EventT>*>(
itr->second.at(x))->OnEvent(event);
}
}
template<typename EventT>
void EventDispatcher::Register(int type, EventListener_Interface<EventT>* listener) {
if (listener == NULL) { return; } // disallow a NULL listener
listeners_[type].push_back(listener);
}
Again, feedback would be greatly appreciated. I would prefer not to use RTTI, but I'm open to suggests.
Thanks.
EDIT: De-virtualized SetHandled and IsHandled in EventBase and removed the ctor and dtor for Event at Ftn's suggestion.
EDIT: Altered Register in EventDispatcher in the way __sprite suggested.