I am writing some message handling code, whereby each message is a POD structure. On way of writing this would be to define an abstract base class, with virtual functiosn for each message type e.g:
class AbstractHandler
{
public:
virtual void handleMessage( const MessageType1& msg ) =0;
virtual void handleMessage( const MessageType2& msg ) =0;
virtual void handleMessage( const MessageType3& msg ) =0;
virtual void handleMessage( const MessageType4& msg ) =0;
};
And then create derived concrete classes that implement the handler functions:
class ConcreteHandler : public AbstractHandler
{
public:
virtual void handleMessage( const MessageType1& msg );
virtual void handleMessage( const MessageType2& msg );
virtual void handleMessage( const MessageType3& msg );
virtual void handleMessage( const MessageType4& msg );
};
If new messages are added to the system AbstractHandler
must be updated along with all derived types.
Alternatively I could hold all supported message types in an mpl
sequence, and use mpl::inherit_linearly
to generate the abstract base class.
( Note: I already use an mpl::vector
of message types elsewhere in the code. )
e.g:
typedef mpl::vector< MessageType1, MessageType2,
MessageType3, MessageType4 > message_types;
template< class Message >
class Wrapper
{
public:
virtual void handleMessage( const Message& msg ) = 0;
protected:
~Wrapper(){}
};
class AbstractHandler
: public mpl::inherit_linearly< message_types
, mpl::inherit< mpl_1, Wrapper< mpl::_2 > >
>::type
{
public:
virtual ~AbstractHandler() {}
};
Concrete handlers then derive from AbstractHandler
. This means that whenever new message types are added to the system it is simply a case of changing the mpl::vector< types... > message_types
sequence, add adding new handleMessage
functions to derived classes.
In my opinion this reduces long term maintenance, since the AbstractHandler will automatically have pure virtual functions for all messages in the mpl::vector message_types
In terms of performance are there any downsides to using this approach?
What are the implications of using mpl::inherit_linearly
to generate abstract base classes?
I've done similar code before (and I'm doing it again today).
There is no cost other than the inheritance-induced costs. Mainly because the final type is determined at compile time, not runtime.
However, this obviously can make your compilation time longer, relative to the message type list size. If like me you also write a message dispatcher class (which can take anything to dispatch to any handler for this type), then it can be expensive on compilation time.
Otherwise, it's good.
Just understand the implication of this kind of setup: the list of messages handled is defined at compile time, not runtime. Some event system are runtime because of the usage requirements. So make sure it's what you want in your use cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With