I have an event emitter that emits events and event handlers that handle events. I can extend the Event
object to make different events like AlarmEvent
, and the EventHandler
object to make AlarmEventHandler
. EventHandler
has a function HandleEvent(Event &event)
. This causes a problem for child classes that may have HandleEvent(AlarmEvent &event)
methods. Obviously these are two different functions so there is no overriding taking place here. I need instead for HandleEvent
to be overridden by the child class.
I fully understand the problem is that each EventHandler
has a different HandleEvent
signature so the EventEmitter
will always handle events with the base EventHandler::HandleEvent
. I thought by using Event &event
as a paremeter to EventEmitter::Emit
it would know what kind of Event
it was dealing with and choose the correct method.
How can I have my EventEmitter
call AlarmEventHandler::HandleEvent
instead of the base method EventHandler::HandleEvent
?
// Example program
#include <iostream>
#include <string>
#include <vector>
// event types
class Event {};
class AlarmEvent : public Event {};
// event handler
class EventHandler {
public:
virtual void HandleEvent(Event event);
};
void EventHandler::HandleEvent(Event event){
std::cout << "Handle event " << std::endl;
}
// alarm event handler
class AlarmEventHandler : public EventHandler {
public:
void HandleEvent(AlarmEvent event);
};
void AlarmEventHandler::HandleEvent(AlarmEvent event){
std::cout << "Handle alarm event " << std::endl;
}
// event emitter
class Emitter {
public:
std::vector<EventHandler*> handlers;
void Emit(Event &event);
};
void Emitter::Emit(Event &event){
for(size_t i = 0; i < this->handlers.size(); i++){
this->handlers[i]->HandleEvent(event);
}
}
int main()
{
AlarmEventHandler handler;
AlarmEvent event;
Emitter emitter;
emitter.handlers.push_back(&handler);
// problem:
// Handle event printed instead of Handle alarm event
emitter.Emit(event);
}
Use a dynamic_cast
!
So your AlarmEventHandler
could look like:
// alarm event handler
class AlarmEventHandler : public EventHandler {
public:
void HandleEvent(const Event &event); // Our polymorphic override
void HandleEvent(AlarmEvent event); // Our custom Alarm logic
};
void AlarmEventHandler::HandleEvent(const Event &event){
try {
HandleEvent(dynamic_cast<const AlarmEvent&>(event));
} catch(const std::exception& e) {
std::cerr << "I can't handle things that aren't AlarmEvents!" << std::endl;
}
}
void AlarmEventHandler::HandleEvent(const AlarmEvent &event){
std::cout << "Handle alarm event " << std::endl;
}
To do this though, you'll need Event
to be a polymorphic class. So you make the destructor virtual
:
class Event {
public: virtual ~Event() {} //Need this so Event is a polymorphic class
};
See it run here: https://ideone.com/KMkLfq