Overriding common method of same templated base class inherited multiple times - c++

Background
I had come across and application where I had access to a method:
void AttachCallback(int event, std::functional<void(int)> cb);
which allowed me to attach a callback cb to event event. I also had several classes that would need to attach callbacks to a couple events in their constructors and implement the callback for each event they bound to. So the first implementation that comes to mind looks like:
class MyClass {
public:
MyClass() {
AttachCallback(0, [this](int value) { cb0(value); });
AttachCallback(2, [this](int value) { cb2(value); });
// ... as necessary
}
private:
void cb0(int value) { /*... callback for event 0 ...*/ }
void cb2(int value) { /*... callback for event 2 ...*/ }
// ... as necessary
};
But, since I've been playing around with templates a lot recently, I wondered if I could create a templated pure-virtual class for listening to a given event and use it as follows:
template<const int EVENT>
class ListensToEvent {
public:
virtual ~ListensToEvent() = default;
protected:
ListensToEvent() {
AttachCallback(EVENT, [this](int value) { cb(value); });
}
virtual void cb(int value) = 0;
};
class MyClass : public ListensToEvent<0>, public ListensToEvent<2> {
private:
void cb(int value) override;
};
template<> // This line makes me suspicious
void MyClass::ListensToEvent<0>::cb(int value) {
/*... callback for event 0 ...*/
}
template<>
void MyClass::ListensToEvent<2>::cb(int value) {
/*... callback for event 2 ...*/
}
When searching around for related topics, I found this thread which shows how to use helper classes to remedy clashes that occur when two base interfaces provide the same identifier pure-virtual method. Since I use templates here, I wouldn't be able to use helpers like that because I don't know how many instantiations there could be, but I found that declaring the method without specialization and then providing template specializations outside the class definition allowed me to target each base classes' method individually (as shown above).
Proof of Concept
While testing this out, I built a simplification of this design (without callbacks) just to show that it compiles and specializes here.
Question
Primarily, I'm concerned with my understanding of why this works. It makes sense to me that I would be able to specify which cb I'm implementing after the class definition by qualifying cb with either ListensToEvent<0> or ListensToEvent<2>. What I don't understand is why that qualification counts as a template specialization and therefore why the line template<> is needed. Additionally, if these qualifications are in fact template specializations, how exactly does C++ view the method specializations and why do they work?
With that said, I'm also interested in comments about the functionality of this design. Is it an efficient way to simplify MyClass and it's other siblings implementations, or would it have been better done the first way I proposed? Or is there another design that would work best in this situation?

Related

How to make SFINAE work to choose template method inherited through multiple inheritance

Trying to implement the observer pattern, I would like that subject and observer represent all possible type of events (avoid duplicated code).
I would like also to allow classes to inherit multiples times from subject to be observable by multiple events, through multiple inheritance. One solution is to make register/notify/etc... methods template, to make it "like" different name but with same code and to disambiguiate the call without having to make a wrapper function.
What I would like to have:
object obj;
obj.registerEvent<Event1>(observer1);
obj.registerEvent<Event2>(observer2);
obj.registerEvent<Event3>(observer3);
...
Actual code:
#include <algorithm>
#include <type_traits>
#include <set>
#include <gtest/gtest.h>
template<typename Event>
class Observer
{
public:
protected:
Observer() = default;
public:
virtual void update() = 0;
};
template<typename Event>
class Subject
{
private:
std::set<Observer<Event>*> m_observers;
protected:
Subject() = default;
public:
#define same_template \
template<class T, class = typename std::enable_if<std::is_same<T, Event>::value>::type>
same_template
void registerObserver(Observer<Event>* observer, Event* = 0)
{
m_observers.insert(observer);
}
same_template
void removeObserver(Observer<Event>* observer, Event* = 0)
{
m_observers.erase(observer);
}
same_template
void notifyObservers()
{
std::for_each(m_observers.begin(), m_observers.end(), [] (Observer<Event> *observer) {
observer->update();
});
}
};
TEST(PatternObserverTest, CompilationTest)
{
struct Move {};
struct Jump {};
struct Player : Subject<Move>, Subject<Jump> {
void move()
{
notifyObservers<Move>(); // ERROR: member found in multiple bases classes of different types
}
void jump()
{
notifyObservers<Jump>(); // ERROR: member found in multiple bases classes of different types
}
};
struct Level : Observer<Move>, Observer<Jump> {
void update()
{
}
};
Player player;
Level level;
player.template registerObserver<Move>(&level); // ERROR: member found in multiple bases classes of different types
}
I even tried to add one foo parameter (Event*) if ever it would break the ODR.
The problem is, to choose the good method override. It look like SFINAE don't work over multiple inheritance. How can I make it work?
My guess:
I thought the compiler makes a set of all possible methods and then, eliminate the wrong candidates by instanciation, and then if there is exactly 1 remaining method, call it, or throw an error.
It look like the compiler does it: it make a set of possible methods and because there is more than one candidate, deduce immedialty that the call is amibiguous because the scopes are differents before even instanciating the methods, by looking at function name only and not function signature.
I know a can make a workaround with a common superclass, and casting (method 2) or generating unique id per type (method 3), but I would like to stuck to C++ that can't compile and crash because of syntax error.
Functions must be in the same scope in order to be subject to overload resolution, and can be introduced to the Player scope with a using declaration:
struct Player : Subject<Move>, Subject<Jump>
{
using Subject<Move>::notifyObservers;
using Subject<Jump>::notifyObservers;
using Subject<Move>::registerObserver;
using Subject<Jump>::registerObserver;
void move()
{
notifyObservers<Move>();
}
void jump()
{
notifyObservers<Jump>();
}
};
DEMO

Is there a way to detect if a function is overridden?

Suppose we have an abstract Base class that is inherited:
class Base
{
protected:
Base() {}
virtual ~Base() {}
virtual void on_event_foo(int) {}
virtual void on_event_bar(int) {}
};
struct Concrete : public Base
{
virtual void on_event_foo(int value) {/*do some stuff with #value*/}
};
Is it a way to know (at compile time would be the best) the virtual functions from Base that was overridden (with some code in constructor, or with a special pattern)?
My purpose is to implement a wrapper for a library that use some callbacks ; and if I can do check the overriden functions, I will create only the callbacks the user wants.
I want the user can choose the function he wants to override. Then in my code, I will create callbacks only for the overridden functions. The pure virtual functions are not a solution, because they cannot permit to create a concrete class without overriding all of them.
In the constructor of Base, for now, I connect a lot of static callback functions of Base within a C API. In those functions, I call the corresponding member function. For example, the callback function is static Base::EventFoo(/* ... */) that calls inside object->on_event_foo(/* .. */). This is because I cannot give a member function as a callback to a C library.
But creating too much callbacks make my wrapper slower. So, I want to connect only the callback that the user wants, ie knowing the functions there are overriden by him.
Disclaimer: I've been notified that this behavior is unspecified since it relies on comparing virtual member function pointers:
[expr.eq] ... if either is a pointer to a virtual member function, the result is unspecified.
Wording is present in all C++ standards (that I could check). Your results may vary.
If you are willing to change a few things, you can use the curiously recurring template pattern to determine if the function is overridden
#include <iostream>
template <class Derived>
struct Base
{
virtual void on_event() {}
void raise_event()
{
if (&Derived::on_event == &Base::on_event)
std::cout << "not overridden" << std::endl;
else
std::cout << "overridden" << std::endl;
}
};
struct Concrete1 : Base<Concrete1>
{
virtual void on_event() override {}
};
struct Concrete2 : Base<Concrete2>
{
// no override
};
int main()
{
Concrete1 c1;
Concrete2 c2;
c1.raise_event(); // prints overridden
c2.raise_event(); // prints not overridden
return 0;
}
The statement &Derived::on_event == &Base::on_event should be resolved at compile-time (if that's what you're worried about) and the if can be optimized away.
Though I agree with others' opinions that this seems like a poor pattern. It would be much simpler to have the base class have empty event handlers like you already have.
Don't use virtual methods at all. If all you want is given some concrete type, Concrete, to hook it up to a bunch of callbacks based on the presence of member functions then we can use templates.
For a given type and function name, we can determine if &T::func exists at compile time. If it does, we add that callback. So we end up with a whole bunch of things like:
template <class T>
void setup_cbs(T& object) {
T* ptr_to_object = ...; // store somewhere
static_if<has_on_event_foo<T>>(
[](auto ptr){
add_event_foo_callback(ptr, [](void* p, int i) {
using U = decltype(ptr);
static_cast<U>(p)->on_event_foo(i);
})
}),
[](auto ){}
)(ptr_to_object);
I'm assuming the callback adder takes a pointer and a callback. You will separately have to figure out how to store the pointers, but that seems easier.
With modern c++ you can do this:
if constexpr (!std::is_same_v<decltype(&Derived::foo), decltype(&Base::foo)>) {
std::cout << "overrided" << std::endl;
}
You may want to define a macro like this:
#define OVERRIDED(B, D, name) !std::is_same_v<decltype(&B::name), decltype(&D::name)>

Is checking of object type really always sign of bad design?

I have a source of some lines of text, each of which is a message, representing object of some type. I'm making a parser for these lines, which should take the text line as input and give the ready to use object as output. So I make the following hierarchy of classes:
class Message
{
public:
virtual ~Message(){};
};
class ObjectTypeA : public Message
{/*...*/};
class ObjectTypeB : public Message
{/*...*/};
class ObjectTypeC : public Message
{/*...*/};
and here's how it's used:
std::shared_ptr<Message> parseLine(std::string& line);
void doWork()
{
std::string line;
while(getLine(line))
{
std::shared_ptr<Message> object=parseLine(line);
if(dynamic_cast<ObjectTypeA*>(object.get()))
doSomethingA(*static_cast<ObjectTypeA*>(object.get()));
else if(dynamic_cast<ObjectTypeB*>(object.get()))
doCompletelyUnrelatedProcessing(*static_cast<ObjectTypeB*>(object.get()));
else if(dynamic_cast<ObjectTypeC*>(object.get()))
doSomethingEvenMoreDifferent(*static_cast<ObjectTypeC*>(object.get()));
}
}
Here the parser would be a library function, and the objects don't know in advance how they will be processed. So, I can't put the processing code to a virtual function of Message implementations.
But many of the answers in this question say that if one needs to check type of the object, it's a sign of bad design. But I can't seem to see what's bad here. Is there any better way to organize the solution?
First off, it's not always a sign of bad design. There are very few absolutes in "soft" things like "good" or "bad" design. Nevertheless, it does often indicate a different approach would be preferable, for one or more of these reasons: extensibility, ease of maintenance, familiarity, and similar.
In your particular case: One of the standard ways to make arbitrary class-specific processing possible without type switches or bloating/polluting the interface of the class is to use the Visitor pattern. You create a generic MessageVisitor interface, teach the Message subclasses to call into it, and implement it wherever you need to process them:
class MessageVisitor;
class Message
{
public:
virtual ~Message(){};
virtual void accept(MessageVisitor &visitor) = 0;
};
class ObjectTypeA : public Message
{
void accept(MessageVisitor &visitor) override
{ visitor.visit(*this); }
/*...*/
};
class ObjectTypeB : public Message
{
void accept(MessageVisitor &visitor) override
{ visitor.visit(*this); }
/*...*/
};
class ObjectTypeC : public Message
{
void accept(MessageVisitor &visitor) override
{ visitor.visit(*this); }
/*...*/
};
class MessageVisitor
{
public:
virtual void visit(ObjectTypeA &subject) {}
virtual void visit(ObjectTypeB &subject) {}
virtual void visit(ObjectTypeC &subject) {}
};
You would then use it like this:
void doWork()
{
struct DoWorkMessageVisitor : MessageVisitor
{
void visit(ObjectTypeA &subject) override { doSomethingA(subject); }
void visit(ObjectTypeB &subject) override { doSomethingB(subject); }
void visit(ObjectTypeC &subject) override { doSomethingC(subject); }
};
std::string line;
while(getLine(line))
{
std::shared_ptr<Message> object=parseLine(line);
DoWorkMessageVisitor v;
object->accept(v);
}
}
Feel free to customise this with const overloads etc. as necessary.
Note that accept cannot be implemented in the base class, because you need the correct type of *this in the invocation of visit. That is where the type switch has "moved".
An alternative is to make the visit functions in MessageVisitor pure virtual instead of empty. Then, if you need to add a new message type, it will automatically force you to update all places where such type-specific processing occurs.
You're really asking for opinions on whats good and bad design. Here's mine:
Yours is bad design, because you try to do something in another class that should be handled by the subclasses, because that's what polymorphism is for.
Your mother class should have a
virtual void do_stuff_that_is_specific_to_the_subclass(...) = 0;
method, which you'd implement in your subclasses.
Here the parser would be a library function, and the objects don't know in advance how they will be processed. So, I can't put the processing code to a virtual function of Message implementations.
Why not? You should simply have a
virtual void do_stuff_that_is_specific_to_the_subclass(parser&, ...) = 0;
method that uses the parser differently for each subclass. There's no reason that what you can do in your if/else clauses couldn't just be done in the subclasses, unless it breaks encapsulation, which I'd doubt, because the only reason you've got these objects is that you want to do specific things differently for different lines.
doSomethingA, doCompletelyUnrelatedProcessing and doSomethingEvenMoreDifferent could be just overrides of pure virtual function of Message class. In your case that would be much more effecient and better as a design solution.

Event Callback Daemon

I am working on an event daemon in C++ that I would like to use member function callbacks. Basically an event queue would collect events which the daemon continuously services. There is a base class Event struct with an ID and all events would derive from it. I would like the methods registered for each event to use the derived event type in their signature.
struct Event
{
unsigned int eventId;
};
struct EventA : public Event
{
unsigned int x;
unsigned int y;
};
// and struct EventB, EventC (use your imagination...)
const unsigned int EVENT_A = 1;
const unsigned int EVENT_B = 2;
const unsigned int EVENT_C = 3;
class Foo
{
public:
void handlerMethod_A(const EventA& e);
void handlerMethod_B(const EventB& e);
};
class Bar
{
public:
void handlerMethod_C(const EventC& e);
};
Then the Daemon would allow these classes to subscribe their member functions using their 'this' pointer.
class EventDaemon
{
public:
void serviceEvents();
template <class CallbackClass, class EventType>
void subscribe(
const unsigned int eventId,
CallbackClass* classInstancePtr,
void (CallbackClass::*funcPtr)(EventType));
private:
Queue<Event*> eventQueue_;
};
So outside this class you could do something like:
EventDaemon* ed = new EventDaemon();
Foo* foo = new Foo();
Bar* bar = new Bar();
ed->subscribe(EVENT_A, foo, Foo::handlerMethod_A);
ed->subscribe(EVENT_B, foo, Foo::handlerMethod_B);
ed->subscribe(EVENT_C, bar, Bar::handlerMethod_C);
And the EventDaemon loop would be along the lines of
void EventDaemon::serviceEvents()
{
while (true)
{
if (eventQueue_.empty())
{
// yield to other threads
}
else
{
// pop an event out of the FIFO queue
Event e* = eventQueue_.pop();
// somehow look up the callback info and use it
classInstancePtr->*funcPtr(reinterpret_cast<?*>(e));
}
}
}
So my question is how I can store the 'this' pointers and member function pointers in some sort of array by event ID. That way I could look up the 'classInstancePtr' and 'funcPtr' by using e->eventId and the event type as well for the reinterpret cast.
You are working too hard. Use boost functions:
http://www.boost.org/doc/libs/1_47_0/doc/html/function.html
These work whether you have a object or not. They will increase your compile time.
Note, whenever you come across these types of questions where you know many people must have had the same problem, there is probably a simple option and, if it is not in the standard library, it is probably in boost.
In response to Nick, I'm constantly throwing boost function objects into vectors and whatnot.
I've found that, while boost function objects can hold object references, having them do so can lead to bugs with object lifetimes and it is better to have them hold copies of the class objects (you run into the same bugs however you try to hold a reference to a object instance that you don't necessarily control the lifetime of). The pattern:
class Foo
{
struct Member
{
// member variable definitions
};
shared_ptr<Member> m_; // the only real member variable
public:
// etc. including the all-important copy
// constructor and assignment operator and
// don't forget the member function that gets stuck into
// the boost function as a callback!
};
where all the member variables get held in a shared_ptr allows for good performance and you don't have to worry about lifetimes of objects held by function objects because you can copy them by value. Threaded code (what I always seem to be writing nowadays) needs additional things like at least one boost mutex element in Member or some other way to assure values don't get stomped on.
boost::function [or, if your system supports it, std::function] will take care of holding the this pointer quite well, with the added benefit of not requiring an actual object if it isn't necessary. So instead of void (SomeType::*)(EventA) you have std::function<void(EventA)>, and you call std::bind as appropriate.
subscribe(EVENT_A, std::bind(&foo::handleEventA, &foo, std::placeholders::_1));
A trivial wrapper function can be used to provide the same signature as you originally proposed and hide the nasty placeholders.
You do, of course, still have the issue of each event type having its own signature, and the need to ensure you use the correct Event ID code. In both cases, your base Event type can help out. Your callback need not accept an EventA&; it can accept an Event&, and dynamic_cast it to an EventA at runtime. For the ID, query the type directly.
struct Event {
virtual void ~Event() { }
virtual int ID() =0;
};
template<typename E>
struct EventHelper : Event {
virtual int ID() { return E::EventID; }
};
struct EventA : EventHelper<EventA> {
static const int EventID = 89;
};
Now, if you have an Event* object [when you go to dispatch your events], you can do p->ID() to get the appropriate ID, and if you have a EventA type [when you register your callbacks] you can do EventA::EventID.
So now, all you have to store is a std::function<void(const Event&)> and an associated int value for each of your callbacks, no matter what the actual type of event you have.
void subscribe(int id, std::function<void(const Event&)> f) {
callbacks.insert(std::make_pair(id, f));
}
template<typename E>
void subscribe(std::function<void(const Event&)> f) {
subscribe(E::EventID, f);
}
template<typename O, typename E>
void subscribe(O* p, void (O::*f)(const Event&)) {
subscribe<E>(std::bind(f, p, std::placeholders::_1));
}
You still have the issue that user error when subscribing can result in a function being called incorrectly. If you've used dynamic_cast correctly within the callback, this will get caught at runtime, but a compile time check would be nice. So what if we automate that dynamic_cast? For this step, I'm going to use c++11 lambdas, but it can be implemented in C++03 as well using a variety of methods.
template <class CallbackClass, class EventType>
void subscribe(CallbackClass* classInstancePtr, void (CallbackClass::*funcPtr)(EventType)) {
subscribe<EventType::EventID>([&](const Event& e) {
(classInstancePtr->*funcPtr)(dynamic_cast<const EventType&>(e));
});
}
So now we've gone full circle back to your original interface where your callbacks accept the actual type they are going to be working on, but internally you've squeezed them all into a common signature.
Okay, so I finished an implementation of my original desired interface. I was looking through Dennis' answer but eventually got lead to functors and I realized what I was looking for was a simple polymorphic solution. I failed to grasp before that I could create a non-templated base class with which to use for storing templated classes in vectors/arrays. I think this is what mheyman was trying to tell me... so I apologize I didn't get it right away. Just to clarify though I was really looking for the implementation solution for my own benefit and knowledge, not just a 3rd party library to get the job done. So I guess I would be looking for how Boost functions work, not just that they exist and are awesome.
If anyone is still interested here are the important parts of what I ended up with (minus some extraneous stuff and error checking):
EventFunctor is basically a pointer to member function template class
EventFunctorBase is the non-templated base class used to store them in a vector
The Event is dynamic cast using the templated type before being used to invoke the callback
class EventDaemon
{
public:
template <class CallbackClass, class EventType>
void subscribe(
const EventId eventId,
CallbackClass* callbackClassInstancePtr,
void (CallbackClass::*funcPtr)(const EventType&));
private:
EventFunctorBase* callbacks_[MAX_NUM_EVENTS];
};
template <class CallbackClass, class EventType>
void EventDaemon::subscribe(
const EventId eventId,
CallbackClass* callbackClassInstancePtr,
void (CallbackClass::*funcPtr)(const EventType&))
{
callbacks_[eventId] = new EventFunctor<CallbackClass,EventType>(callbackClassInstancePtr,funcPtr);
}
class EventFunctorBase
{
public:
EventFunctorBase();
virtual ~EventFunctorBase();
virtual void operator()(const Event& e)=0;
};
template <class CallbackClass, class EventType>
class EventFunctor : public EventFunctorBase
{
public:
EventFunctor(
CallbackClass* callbackClassInstancePtr,
void (CallbackClass::*funcPtr)(const EventType&));
virtual void operator()(const Event& e);
private:
CallbackClass* callbackClassInstancePtr_;
void (CallbackClass::*funcPtr_)(const EventType&);
};
template <class CallbackClass, class EventType>
EventFunctor<CallbackClass,EventType>::EventFunctor(
CallbackClass* callbackClassInstancePtr,
void (CallbackClass::*funcPtr)(const EventType&))
:
callbackClassInstancePtr_(callbackClassInstancePtr),
funcPtr_(funcPtr)
{
}
template <class CallbackClass, class EventType>
/*virtual*/ void EventFunctor<CallbackClass,EventType>::operator()(const Event& e)
{
(callbackClassInstancePtr_->*funcPtr_)(dynamic_cast<const EventType&>(e));
}
EventDaemon loop
while (true_)
{
if (eventQueue_->empty())
{
// yield to other threads
}
else
{
Event* e = eventQueue_.pop();
(*(callbacks_[e->ID]))(*e);
}
}
My final steps here will be to try and remove the need to have the developer define an ID for each event... of course this might end up a new post later this week.

Passing type information to function in lieu of virtual template function C++

I have a base class which implements the following:
struct Consumer
{
template <typename T>
void callback(T msg) { /*null implementation */ }
};
I then have a class implement this:
struct Client : public Consumer
{
void callback(Msg1 msg);
void callback(Msg2 msg);
void callback(Msg3 msg);
};
The issue is I have a container of Client objects treated as Consumer* and I can't think of a way to get these Consumer objects to call the derived functions. My intended functionality is to have multiple Clients each of which implement an overloaded function for each Msg class that means something to them and the rest of the calls simply call the null implementation in the base class
Any thoughts how I can get the derived class to be called? Right now I need to implement every overloaded function in Consumer and mark them as virtual.
Cheers,
Graeme
If you really don't want to use virtual functions (this seems to be a perfect use case for them actually, but I don't know about your message classes), you can use the CRTP:
template <typename U>
struct Consumer
{
template <typename T>
void callback(T msg)
{ static_cast<U*>(this)->callback(msg); }
};
struct Client : Consumer<Client>
{
void callback(Msg1 msg);
void callback(Msg2 msg);
void callback(Msg3 msg);
};
The problem, of course, is that you cannot store Consumer objects in a container any more. Since everything is compile time, the actual type of the client must be stored alongside the consumer object for the compiler to call the right callback function. Virtual functions allow you to wait until runtime for this...
Is there a reason not to have Msg classes polymorphic and use standard virtual functions (other than "I have to rewrite all the code and I cannot") ?
EDIT If your concern is about message classes, why not use something like that, assuming message classes implement a DoSomething member function: (this technique is known as Type Erasure)
struct AnyMsg
{
template <typename Msg>
AnyMsg(Msg x) : impl(newImpl(x)) {}
void DoSomething() { impl->DoSomething(); }
private:
struct Impl
{
virtual ~Impl() {}
virtual void DoSomething() = 0;
};
// Probably better is std::unique_ptr if you have
// C++0x. Or `boost::scoped_ptr`, but you have to
// provide copy constructors yourself.
boost::shared_ptr<Impl> impl;
template <typename Msg>
Impl* newImpl(Msg m)
{
class C : public Impl
{
void DoSomething() { x.DoSomething(); }
Msg x;
public:
C(Msg x) : x(x) {}
};
return new C(m);
}
};
You can customize the behavior of newImpl to get what you want (eg. default actions if there is no DoSomething member function in the message class, specialization for some message classes or anything else). This way, you implement Msg classes like you would have done with your template solution, and you have a unique facade that you can pass to the virtual functions in your client classes.
If the Message classes are going to be very different, and client classes may react differently to them, and you are going to have a lot of message classes, this begins to smell. Or perhaps you have a candidate for the ugly and scary Visitor pattern.
Since you don't want to use virtual methods, the compiler would have to know statically (i.e. at compile time) which function to call. If you have different client objects in your container, there is now way the compiler could possibly know this. So I think there's no solution to your problem without using virtual methods (which are btw. exactly designed for this kind of situations...).
Of course you could alternatively using some switch statements for manually deriving the concrete type, but this is neither elegant nor efficient (and you would have to hardcode all possible client types ...)
EDIT
Personally, I'd implement some base message class containing a type code and implement a switch statement in the client class to handle different message types like:
struct MsgBase {
int type;
};
struct Consumer {
virtual void callback(MsgBase msg) { };
};
struct Client : public Consumer {
void callback(MsgBase msg) {
switch (msg.type) {
case MSGTYPE1:
callback((Msg1)msg);
break;
case MSGTYPE2:
callback((Msg2)msg);
break;
// ...
}
}
void callback(Msg1 msg) { /* ... */ }
void callback(Msg2 msg) { /* ... */ }
};
You could also make MsgBase polymorphic (e.g. virtual destructor) and use typeid to differentiate (more elegant but slightly less efficient ...)
struct Client : public Consumer {
void callback(MsgBase* msg) {
if (typeid(*msg) == typeof(Msg1))
callback(static_cast<Msg1*>(msg));
else if (typeid(*msg) == typeof(Msg2))
callback(static_cast<Msg2*>(msg));
}
// ...
};
This is always a difficult situation to make totally extensible, as is the case usually with the Visitor pattern.
You end up needing up to V*T implementations where V is the number of "visitors" and T is the number of types being visited and will probably end up having to use a mixture of visitor and class factory pattern.
visitors here would be your consumers
class factory would be used for the message types.
and your best way to make it totally extensible is to create new function "objects" for message/consumer pairs and a bit of double-dispatch to ensure the right one gets called.
In your case you have different messages come in and then you give them to your consumers who might handle them? So each message should have an identifiable "type" and your consumer
should look up this type in a table to create a handler for it.
You can have one handler per type per consumer class.