I think he means something like
class Listener
{
public:
virtual void listen( unsigned int MessageID , void *AdditionalInformation )
{
}
//or pure virtual
};
struct MessageA
{
const static unsigned int ID = 0; //or put IDs in a seperate enum
//no data
};
struct MessageB
{
const static unsigned int ID = 1;
char data[10];
};
class SomeListener
: public Listener
{
public:
void listen( unsigned int ID , void *AdditionalInformation )
{
switch( ID )
{
case MessageA::ID:
//....
break;
case MessageB::ID:
MessageB &message = *reinterpret_cast< MessageB* >( AdditionalInformation );
//.....
break;
}
};
};
int main()
{
SomeListener derived;
Listener &base = derived;
base.listen( MessageA::ID , &MessageA() );
MessageB message_b;
//set data
base.listen( MessageB::ID , &message_b );
}
I don't see how this approach is simpler then the one I showed, it definitely has more boilerplate than my example.
I may be wrong, but I think the template solution is faster:
template version overhead:
- virtual function call with 1 parameter: constant time
cast - version:
- virtual function call with 2 parameters: constant time
- switch statement: depending on compiler optimizations either constant time (jump table) , logarithmic (binary search) or linear (naive search)
However, since the compiler has to create a vtable with entries for each message for each specific listener, the template version consumes probably more memory, increasing with both the number of your messages and the number of your listeners (classes).
Your example pretty much demonstrates exactly what I would do. Template based message filtering is one of the things I tried but again, for simplicity i recommend the message ID + casting method. The amount of boilerplate required to handle messages in a simple scenario seems to be increased, but as your number of message types increases, your template based version will use huge amounts of memory and be considerably complicated. I'm not sure how you would implement decorators, relays, or other types of message handlers with the templated version either - would it require you to do something like,
MessageHandler<MessageA, MessageB, MessageC, MessageD, MessageE, MessageF, MessageG, MessageH, MessageI, MessageJ, MessageK, MessageL>