I have an event handler. It receives an event and needs to do some work on it. That work is split between common work - things that have to be done for all types of event handler - and specific work - things that only need to be done for a specific app.
There seem to be two approaches to implementing this design. I could write a non-virtual
member function, that invokes a differently named pure virtual
member function:
struct Base {
virtual ~Base() = default;
void onEvent(Event const& ev) {
// do common stuff
onEventImpl(ev);
}
protected:
virtual void onEventImpl(Event const& ) = 0;
};
or, I could have a single virtual
member function and rely upon the derived classes to always call the Base class first:
struct Base {
virtual ~Base() = default;
virtual void onEvent(Event const& ev) {
// do common stuff
}
};
struct Derived : Base {
void onEvent(Event const& ev) override {
Base::onEvent(ev);
// do specific stuff
}
};
The former is safe, but involves having two of every function named basically the same.
The latter is error-prone in that the derived classes could forget to call the base class (although this error would be readily apparent from the first test - not the kind of subtle error that could creep up on you), but at least we just have the one onEvent()
function.
What's the right approach to solving this problem? Is there a better option than these two?