How call a method on all step of class derivation hierarchy? - c++

Take this example:
#include <iostream>
#include <typeindex>
#include <vector>
#include <map>
class _IEventHandler {}; // just for abstract template type
class IEvent {
public:
virtual void visitEventHandler(_IEventHandler *handler) = 0;
};
#define EXTENDS(type, parentType) \
public: \
using ParentClass = parentType; \
void visitEventHandler(_IEventHandler* handler) override { \
static_cast<IEventHandler<type>*>(handler)->on(*this); \
} \
template<typename Event>
class IEventHandler : public _IEventHandler {
public:
//virtual void on(Event& e) = 0;
void on(Event &e) {
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
class EventA : public IEvent {
EXTENDS(EventA, IEvent)
};
class EventB : public EventA {
EXTENDS(EventB, EventA)
};
class EventC : public EventB {
EXTENDS(EventC, EventB)
};
class EventD : public EventC {
EXTENDS(EventD, EventC)
};
class EventBus {
public:
void fire(IEvent *event) {
while (typeid(*event) != typeid(IEvent)) {
for (_IEventHandler *handler : m_handlers[typeid(*event)])
event->visitEventHandler(handler);
// Need to update event so the loop progresses. Need to upper cast?
}
}
template<typename T>
void hook(IEventHandler<T> *handler) {
m_handlers[typeid(T)].push_back(handler);
}
protected:
std::map<std::type_index, std::vector<_IEventHandler *>> m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
I would like when I fire a IEvent it call on(EventX& e) on all intermediate derived class and stop on abstract class IEvent.
Currently I don't find solution, I looked about dyn_cast with a typeid, using decltype to access a static method from a instance (yes it's not the basic usage of these operators ;) and not permitted).
Summary:
The goal is to build an event system that supports hooking handlers and firing events. Events are hierarchical, deriving from a common ancestor class. Handlers should be called for their nominal event type and all types derived from that.
So far, the EventBus class is able to call handlers for the specific event type that was fired. The handlers are organized in a map from type_index to a vector of handlers. Getting the entry for a specific event type is not a problem, but how to get the less-derived types?

This is currently solve my issue:
#include <iostream>
#include <typeindex>
#include <vector>
#include <map>
class _IEventHandler {}; // just for abstract template type
class IEvent {
public:
virtual void visit_IEventHandler(std::type_index _index, _IEventHandler *handler) {}
virtual std::type_index getParentTypeIndex(std::type_index index) {
return typeid(IEvent);
}
};
#define EXTENDS(type, parentType) \
public: \
using Class = type; \
using ParentClass = parentType; \
std::type_index getParentTypeIndex(std::type_index index) { \
if (index == typeid(type)) \
return typeid(ParentClass); \
else \
return ParentClass::getParentTypeIndex(index); \
} \
#define HIERARCHICAL_VISITOR(interfaceType, reelType, methodName) \
public: \
void visit##interfaceType(std::type_index _index, interfaceType* _instanceToVisit) override { \
if (_index == typeid(Class)) \
static_cast<reelType<Class>*>(_instanceToVisit)->methodName(*this); \
else \
ParentClass::visit##interfaceType(_index, _instanceToVisit); \
} \
template<typename Event>
class IEventHandler : public _IEventHandler {
public:
//virtual void on(Event& e) = 0;
void on(Event &e) {
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
class EventA : public IEvent {
EXTENDS(EventA, IEvent)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventB : public EventA {
EXTENDS(EventB, EventA)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventC : public EventB {
EXTENDS(EventC, EventB)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventD : public EventC {
EXTENDS(EventD, EventC)
HIERARCHICAL_VISITOR(_IEventHandler, IEventHandler, on)
};
class EventBus {
public:
void fire(IEvent *event) {
std::type_index index = typeid(*event);
while (index != typeid(IEvent)) {
for (_IEventHandler *handler : m_handlers[index])
event->visit_IEventHandler(index, handler);
index = event->getParentTypeIndex(index);
}
}
template<typename T>
void hook(IEventHandler<T> *handler) {
m_handlers[typeid(T)].push_back(handler);
}
protected:
std::map<std::type_index, std::vector<_IEventHandler *>> m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
/*
handle 6EventD
handle 6EventC
handle 6EventA
handle 6EventA
Process finished with exit code 0
*/
The only way that I found is use the basic inheritance process with the typeid check at all stage. I don't know if is the best way, I looking for a better way ;)

The keywords for this answer are "simplify" and "encapsulate".
Let's start with simplifications. There are several elements of the question's code that serve no purpose other than making the code more complicated than it needs to be. (There might be a small performance benefit, but it is premature to worry about that.) In order to better see what the actual solution is, I think it is useful to include these improvements. On the other hand, these are only indirectly related to the actual solution, so I will refrain from giving a detailed rationale for each of these.
Rename _IEventHandler to BaseEventHandler to comply with naming requirements.
Make on() a virtual function in BaseEventHandler so that visitEventHandler() does not need a static_cast.
Make visitEventHandler() a non-virtual function since all implementations are now the same.
Declare ~IEvent() to be virtual so that IEvent still has a virtual function.
Remove the EXTENDS macro because (macros are evil and) the things it defines are no longer used.
Moving on to encapsulation, let's look at the problem from the point of view of EventBus. This class is responsible for triggering handlers in response to events. It has inferred which event each handler wants, and organized the handlers by those event types. This already breaks encapsulation a bit since the bus uses knowledge about the handler's innards. Now they want me to also know about inheritance among the event types??? I need more information or you can go handle it yourself!
Since encapsulation encourages less information, rather than more, let's consider the other option: handle it yourself! Er, let the handlers decide if they want to handle an event. This simplifies EventBus since it no longer needs to be concerned about event types. Its map containing vectors can become a single vector, its hook() method no longer needs to be a template, and its fire() method can drop the loop that has been so difficult to implement. The trade-off is that the event handlers now need to examine the event types. Fortunately, dynamic_cast makes the check very simple.
#include <iostream>
#include <vector>
#include <map>
class IEvent;
/* ** Event handler ** */
class BaseEventHandler {
public:
virtual void on(IEvent &) = 0;
};
template<typename Event>
class IEventHandler : public BaseEventHandler {
public:
void on(IEvent & e) override {
// Only fire for events of the templated type.
if ( dynamic_cast<Event *>(&e) )
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
/* ** Event ** */
class IEvent {
public:
virtual ~IEvent() {} // To force run time type information (RTTI)
void visitEventHandler(BaseEventHandler* handler)
{
handler->on(*this);
}
};
class EventA : public IEvent {};
class EventB : public EventA {};
class EventC : public EventB {};
class EventD : public EventC {};
/* ** Event Bus ** */
class EventBus {
public:
void fire(IEvent *event) {
for (BaseEventHandler *handler : m_handlers)
event->visitEventHandler(handler);
}
void hook(BaseEventHandler *handler) {
m_handlers.push_back(handler);
}
protected:
std::vector<BaseEventHandler *> m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
std::cout << "Firing event D.\n";
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
std::cout << "\nFiring event B.\n";
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
Some things to note about this approach:
Event handlers are fired in the order in which they were hooked. Previously, the order was handlers for the most derived class in the order they were hooked, followed by handlers for that class's direct parent in the order they were hooked, etc. If this is an important consideration, see my other answer.
There are still some issues with this code, but I am willing to chalk them up to being artifacts arising from the need to minimize the example.
There is no need to #include <typeindex>! This is good. I consider use of that header to be a yellow flag for design flaws. Better than a red flag (such as macros), but still an indication that maybe there's a better way to do things.

The keywords for this answer are "simplify" and "delegate".
Let's start with simplifications. There are several elements of the question's code that serve no purpose other than making the code more complicated than it needs to be. (There might be a small performance benefit, but it is premature to worry about that.) In order to better see what the actual solution is, I think it is useful to include these improvements. On the other hand, these are only indirectly related to the actual solution, so I will refrain from giving a detailed rationale for each of these.
Rename _IEventHandler to BaseEventHandler to comply with naming requirements.
Make on() a virtual function in BaseEventHandler so that visitEventHandler() does not need a static_cast.
Remove the EXTENDS macro because (macros are evil and) the things it defines either are no longer used or will be defined elsewhere.
Moving on to delegation, let's look at why EventBus has trouble traversing the inheritance tree of events. One reason is straight-forward: EventBus is not an event. Instead of trying to replicate the inheritance tree, let's use existing elements of the language. Instead of trying to deduce things about events, let's hand the problem off to someone who knows better, namely the event itself.
What I have in mind is a shift of responsibilities, basically shifting most of EventBus::fire() to the events' visitEventHandler(). Since each class knows its parent, it can invoke its parent's version of visitEventHandler(), stepping up the hierarchy until the end is reached. The trade-off is that the type of the map becomes public knowledge, rather than merely a private implementation detail of EventBus. Probably a fair trade.
#include <iostream>
#include <typeindex>
#include <vector>
#include <map>
class IEvent;
/* ** Event handler ** */
class BaseEventHandler {
public:
virtual void on(IEvent &) = 0;
};
template<typename Event>
class IEventHandler : public BaseEventHandler {
public:
void on(IEvent &) override {
std::cout << "handle " << typeid(Event).name() << std::endl;
}
};
using HandlerMap = std::map<std::type_index, std::vector<BaseEventHandler *>>;
/* ** Event ** */
class IEvent {
public:
// This is not an actual event type, so there are no handlers to visit.
virtual void visitEventHandlers(HandlerMap &) = 0;
};
// Need a definition for derived classes to call:
void IEvent::visitEventHandlers(HandlerMap &) {}
template<class Base>
class EventFrom : public Base {
public:
void visitEventHandlers(HandlerMap & handlers) override
{
// Visit the handlers for this specific event type.
for (BaseEventHandler *handler : handlers[typeid(EventFrom)])
handler->on(*this);
// Visit the handlers for the parent event type.
Base::visitEventHandlers(handlers);
}
};
using EventA = EventFrom<IEvent>;
using EventB = EventFrom<EventA>;
using EventC = EventFrom<EventB>;
using EventD = EventFrom<EventC>;
/* ** Event Bus ** */
class EventBus {
public:
void fire(IEvent *event) {
event->visitEventHandlers(m_handlers);
}
template<typename T>
void hook(IEventHandler<T> *handler) {
m_handlers[typeid(T)].push_back(handler);
}
protected:
HandlerMap m_handlers{};
};
int main() {
EventBus eb{};
IEventHandler<EventD> ehd{};
IEventHandler<EventC> ehc{};
IEventHandler<EventA> eha{};
eb.hook(&ehd);
eb.hook(&ehc);
eb.hook(&eha);
EventD eD{};
EventB eB{};
std::cout << "Firing event D.\n";
eb.fire(&eD); // need to stdout handle EventD handle EventC handle EventA
std::cout << "\nFiring event B.\n";
eb.fire(&eB); // need to stdout handle EventA
return 0;
}
Some things to note about this approach:
There is quite a bit of complexity used to make sure all event handlers for the most derived class are fired before any handlers for less derived classes. If this is not important, see my other answer.
There are still some issues with this code, but I am willing to chalk them up to being artifacts arising from the need to minimize the example.
There are no macros! (Macros are a red flag, indicating a likely design flaw.)
I would change the signature of hook() to void hook(BaseEventHandler *handler). While this means changes like eb.hook(&ehd) to eb.hook<EventD>(&ehd), it gives more freedom in defining your event handlers (no need for the IEventHandler template). Probably a good trade.

Related

Using template type to generate unique member names for that template type

This use case comes from wanting to implement a compile-time event bus data structure that only listens/registers/unregisters specifically for the provided template arguments.
Starting with a naive implemention lets say we have the following classes AListener, AEvent, BListener, BEvent.
I want my EventBus class to look like this:
class EventBus {
std::vector<AListener*> aListeners;
std::vector<BListener*> bListeners;
public:
void registerListener(AListener& listener);
void unregisterListener(AListener& listener);
void sendEvent(AEvent event);
void registerListener(BListener& listener);
void unregisterListener(BListener& listener);
void sendEvent(BEvent event);
};
Is there a way I can template it and recursively construct the class? For example:
EventBus<AListener, AEvent, BListener, BEvent> eventBus;
AListener aListener;
eventBus.registerListener(aListener);
AEvent aEvent;
eventBus.sendEvent(aEvent);
BListener bListener;
eventBus.registerListener(bListener);
BEvent bEvent;
eventBus.sendEvent(bEvent);
Preferably it'd be nice to make a new vector for each listener type because it would be inefficient to put all the pointers in one list since a long list of irrelevant listeners would be a waste of performance. Since the event bus is going to have a lot of events going through it, performance is important. Iterating over only the ones we care about is desired.
Finally, assume that we will not specialize any listener so we don't have to worry about inheritance here, all classes in the template list are considered to be final.
My problem:
How do I get around naming? While I assume specializing templates in the recursive definition via method overloading is okay because the compiler will hopefully do the ideal thing... I'm not sure how to handle the different member names.
My plan was to take the list and pull off two members, sort of like this (NOTE this is pseudo-code and almost certainly does not compile, or if it does it is by pure chance):
// Pseudocodey C++ template rough idea
template <typename Listener, typename Event, typename Args...>
class EventBus : public EventBus<Args...> {
// ???
public:
void registerListener(Listener& listener) {
// emplace back
}
void unregisterListener(Listener& listener) {
// erase remove
}
void sendEvent(Event event) {
// send for each
}
};
Of course unless there is a better way? Is this possible?
I would create a class to handle Listener/event:
template <typename Listener, Event>
class EventHandler {
std::vector<Listener*> mListeners;
public:
void registerListener(Listener& listener);
void unregisterListener(Listener& listener);
void sendEvent(Event event);
};
Then, your class which handles all would be:
template <typename ... Ts>
class EventBus : Ts...
{
public:
using Ts::registerListener...; // Requires C++17
using Ts::unregisterListener...; // Prior that you have to do it with recursion
using Ts::sendEvent...; // class EventBus<T, Rest...> : T, EventBus<Rest...>
};
With usage:
EventBus<EventHandler<AListener, AEvent>, EventHandler<BListener, BEvent>> eventBus;
Btw, Event is probably dependent of Listener, so having typename Listener::Event seems appropriate and remove all Event template parameters.
You can use a tuple and some type traits:
#include <iostream>
#include <vector>
#include <tuple>
#include <utility>
template<typename x_Event> class
t_EventTrait;
template<typename ... x_Listener> class
t_EventBus
{
private: ::std::tuple<::std::vector<x_Listener *>...> m_listeners;
public: template<typename xx_Listener> void
Register_Listener(xx_Listener & listener)
{
::std::get<::std::vector<xx_Listener *>>(m_listeners).emplace_back(&listener);
}
public: template<typename x_Event> void
Send_Event(x_Event & event)
{
for(auto p_listener: ::std::get<::std::vector<typename t_EventTrait<x_Event>::t_Listener *>>(m_listeners))
{
p_listener->On_Event(event);
}
}
};
struct t_EventA {};
struct t_ListenerA { void On_Event(t_EventA &) { ::std::cout << "handling A\n"; } };
template<> class t_EventTrait<t_EventA>{ public: using t_Listener = t_ListenerA; };
struct t_EventB {};
struct t_ListenerB { void On_Event(t_EventB &) { ::std::cout << "handling B\n"; } };
template<> class t_EventTrait<t_EventB>{ public: using t_Listener = t_ListenerB; };
int main()
{
t_EventBus<t_ListenerA, t_ListenerB> bus{};
t_ListenerA a{};
bus.Register_Listener(a);
t_EventA ea{};
bus.Send_Event(ea);
t_ListenerB b{};
bus.Register_Listener(b);
t_EventB eb{};
bus.Send_Event(eb);
return 0;
}
online compiler
In C++11, you can use a variadic template
template<class... MoreEventPairs> class EventBus {};
template<class Listener, class Event>
class EventBus<Listener, Event>
{
private:
std::vector<Listener *> Listeners;
public:
EventBus() {};
~EventBus() {};
void registerListener(Listener& listener) {}; // dummy implementations here
void unregisterListener(Listener& listener) {};
void sendEvent(Event event) {};
};
template<class Listener, class Event, class ... MoreEventPairs>
class EventBus<Listener, Event, MoreEventPairs ...> : public EventBus<Listener, Event>,
public EventBus<MoreEventPairs ...>
{
public:
// these are needed so name resolution works
// one needed for each function, on both inheritance paths
using EventBus<Listener, Event>::registerListener;
using EventBus<Listener, Event>::unregisterListener;
using EventBus<Listener, Event>::sendEvent;
using EventBus<MoreEventPairs ...>::registerListener;
using EventBus<MoreEventPairs ...>::unregisterListener;
using EventBus<MoreEventPairs ...>::sendEvent;
};
// construct as
EventBus<ListenerA, EventA, ListenerB, EventB> bus;
This works by essentially peeling two types at a time from the parameter pack. It will not compile if you supply an odd number of types when constructing (e.g. leave off an Event type). You can specialise handling for a particular type of Listener or associated Event by using specialisation of the two-parameter template.
Before C++11, you could use multiple inheritance, but would need to construct the EventBus class separately. This is more effort to maintain, due to need to replicate code to extend.
template<class Listener, class Event> class ListenerBus
{
private:
std::vector<Listener *> Listeners;
public:
ListenerBus() {};
~ListenerBus() {};
void registerListener(Listener& listener) {}; // dummy implementations here
void unregisterListener(Listener& listener) {};
void sendEvent(Event event) {};
};
// AListener, AEvent, etc are concrete classes
class EventBus : public ListenerBus<AListener, AEvent>,
public ListenerBus<BListener, BEvent>
// list other types here
{
public:
using ListenerBus<AListener, AEvent>::registerListener;
using ListenerBus<AListener, AEvent>::unregisterListener;
using ListenerBus<AListener, AEvent>::sendEvent;
using ListenerBus<BListener, BEvent>::registerListener;
using ListenerBus<BListener, BEvent>::unregisterListener;
using ListenerBus<BListener, BEvent>::sendEvent;
// need to replicate above for every base class for name resolution
};
// construct as
EventBus bus;
The registerListener(), unregisterListener(), and sendEvent() member functions are all non-virtual since you don't want them to be over-ridden by EventBus (which will then be affected by the hiding rule).
In addition to assuming no inheritance relationships between any Listener or Event classes, both approaches above assume the Listener and Event classes are all distinct types (i.e. no Listener class or Event class listed more than once). The most likely outcome, if you break that assumption, will be that calls of some of the member functions will become ambiguous.

How to use composition instead of inheritance when dependency injection is involved?

I have a bunch of checkers in my program that I modelled as classes: check the RAM is OK, check the disk is OK, check the temperatures are OK, etc. These checkers have a lot in common, so I modelled them with inheritance: all that is in common goes into a base class CheckerBase that is derived from by specialised classes with checker-specific functionality and dependencies.
However I've often read that composition should be preferred over inheritance, so I'm wondering how this would be done in C++ with composition?
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
using namespace std;
/** Dependencies of various checkers that I pass in via dependency injection. */
struct ErrorReporter {
void report_error(string myMsg) {
cout << myMsg;
}
};
struct TemperatureSensor {
int get_cpu_temp() { return 42; }
int get_disk_temp() { return 32; }
};
struct DiskStressor {
void stress_disk() { }
};
/** Contains dependencies that are common to all checkers.. */
class CheckerBase {
public:
CheckerBase(ErrorReporter* errReporter ) :
mErrReporter(errReporter) { }
virtual void runTest() = 0;
protected:
ErrorReporter* mErrReporter;
};
/** Needs `TemperatureSensor` dependency. */
class TemperatureChecker : public CheckerBase {
public:
TemperatureChecker(ErrorReporter* errReporter,
TemperatureSensor* tempSensor) :
CheckerBase(errReporter), mTempSensor(tempSensor) { }
void runTest() override {
if (mTempSensor->get_cpu_temp() > 42) {
mErrReporter->report_error("CPU too hot");
}
};
private:
TemperatureSensor* mTempSensor;
};
/** Needs `TemperatureSensor` and `DiskStressor` dependencies. */
class DiskChecker : public CheckerBase {
public:
DiskChecker(ErrorReporter* errReporter, TemperatureSensor* tempSensor,
DiskStressor* diskStressor) :
CheckerBase(errReporter), mTempSensor(tempSensor) { }
void runTest() override {
mDiskStressor->stress_disk();
mTempSensor->get_disk_temp();
if (mTempSensor->get_cpu_temp() > 32) {
mErrReporter->report_error("HDD too hot after strees test");
}
};
private:
TemperatureSensor* mTempSensor;
DiskStressor* mDiskStressor;
};
/** Periodically runs each checker. */
class MasterChecker {
public:
MasterChecker() :
mTempChecker { &mErrReporter, &mTempSensor },
mDiskChecker { &mErrReporter, &mTempSensor, &mDiskStressor },
mAllCheckers({&mTempChecker, &mDiskChecker}) {};
void start() {
// In reality I use a timer that continously runs each checker at
// a certain interval.
while (true) {
for (CheckerBase *checker : mAllCheckers) {
checker->runTest();
}
this_thread::sleep_for(chrono::milliseconds(5000));
}
}
private:
ErrorReporter mErrReporter;
TemperatureSensor mTempSensor;
DiskStressor mDiskStressor;
DiskChecker mDiskChecker;
TemperatureChecker mTempChecker;
vector<CheckerBase*> mAllCheckers;
};
int main() {
MasterChecker master;
master.start();
}
EDIT: Updated to include an approximation of how the checkers are used. A MasterChecker runs all the individual checkers periodically. It has a list of the checkers and calls their runTest() member function--which all checkers override from their base class.
... composition should be preferred over inheritance
That means, where you could choose either, prefer composition. In this case, MasterChecker (correctly) composes the various concrete checkers, as your advice recommended.
The fact that the individual checkers inherit/implement an abstract base class isn't a problem, because you can't compose an interface. There's no choice here, and the advice didn't say you should never use inheritance even when composition isn't an alternative.
The case your advice actually warns against is doing something like:
class MasterChecker: public DiskChecker, public TemperatureChecker
where inheritance is abused to aggregate the base class subobjects.
In your case this probably wouldn't work well anyway, at least without changes, due to initialization order and diamond-shaped inheritance reasons.

Generic observer pattern in C++

In many cases in my application i need class A to register itself as a listener on class B to receive notification when something happens. In every case i define a separate interface B implements and A can call do. So for example, A will have the following method:
void registerSomeEventListener(SomeEventListener l);
Also, in many cases, B will need to support multiple listeners so i reimplement the registration and notifyAll logic.
One generic way i know is to have some EventListener (implement by A) and EventNotifier (implement by B) classes. In this case each event is identified by a string and A implements the method:
void eventNotified(string eventType);
I think this is not a good solution. It will result in many if-else statements in case A listens to several events and might result in bugs when event names are changed only in the listener or the notifier.
I wonder what is the correct way to implement the observer pattern in C++?
Take a look at boost::signals2. It provides a generic mechanism to define "signals" where other objects can register. The signal owner can then notify observers by "firing" the signal. Instead of register-methods, the subject defines signals as members which then keep track of connected observers and notify them when initiated. The signals are statically typed and accept every function with the matching signature. This has the advantage that there is no need for inheritance and thus a weaker coupling than the traditional observer inheritance hierarchy.
class Subject {
public:
void setData(int x) {
data_ = x;
dataChanged(x);
}
boost::signals2<void (int)> dataChanged;
private:
int data_;
};
class Observer {
public:
Observer(Subject& s) {
c_ = s.dataChanged.connect([&](int x) {this->processData(x);});
}
~Observer() {
c_.disconnect();
}
private:
void processData(int x) {
std::cout << "Updated: " << x << std::endl;
}
boost::signals2::connection c_;
};
int main() {
Subject s;
Observer o1(s);
Observer o2(s);
s.setData(42);
return 0;
}
In this example, the subject holds some int data and notifies all registered observers when the data is changed.
Lets say you have a generic event fireing object:
class base_invoke {
public:
virtual ~base_invoke () {};
virtual void Invoke() = 0;
}
But you want to fire events on different types of objects, so you derive from base:
template<class C>
class methodWrapper : public base_invoke {
public:
typedef void (C::*pfMethodWrapperArgs0)();
C * mInstance;
pfMethodWrapperArgs0 mMethod;
public:
methodWrapper(C * instance, pfMethodWrapperArgs0 meth)
: mInstance(instance)
{
mMethod = meth;
}
virtual void Invoke () {
(mInstance->*mMethod)();
}
}
Now if you create a wrapper for a collection of pointers to base_invoke you can call each fireing object and signal whichever method on whichever class you'd like.
You can also turn this collection class into a factory for the fireing objects. to simplyfy the work.
class Event {
protected:
Collection<base_invoke *> mObservers;
public:
// class method observers
template<class C>
void Add (C * classInstance, typename methodWrapper<C>::pfMethodWrapperArgs0 meth) {
methodWrapper<C> * mw = NEW(methodWrapper<C>)(classInstance, meth);
mObservers.Add(ObserverEntry(key, mw));
}
void Invoke () {
int count = mObservers.Count();
for (int i = 0; i < count; ++i) {
mObservers[i]->Invoke();
}
}
};
And your done with the hard work. Add an Event object anyplace you want listeners to subscribe. You'll probably want to expand this to allow removal of listeners, and perhaps to take a few function parameters but the core is pretty much the same.

How pass data to 'generic' observer? As arguments or as a single struct?

I am busy adding a generic observer mechanism to a legacy C++ application (using Visual Studio 2010, but not using .Net, so .Net delegates are out of the question).
In the design I want to separate the application-specific part as much as possible from the generic observer mechanism.
The most logical way of implementing observers seems this way:
class IDoThisObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
For every type of observer (IDoThisObserver, IDoThatObserver, ...) the arguments of the methods (handleDoThis, handleDoThat) are different.
What remains in a generic way of storing the observers, like this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (T &t) {m_observers.push_back(&t);}
private:
std::list<T*> m_observers;
};
Calling an observer can't be generalized since the arguments are different for every observer type.
An alternative way would be to 'pack' all arguments into one argument, like this:
struct DoThisInfo
{
DoThisInfo (int arg1, int arg2) : m_arg1(arg1), m_arg2(arg2) {}
int m_arg1;
int m_arg2;
};
And then define a more generic observer, like this:
template<typename T>
class IObserver
{
public:
void notify(const T &t) = 0;
};
And a collection of these observers would then become this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (IObserver<T> &obs) {m_observers.push_back(&obs);}
private:
std::list<IObserver<T>*> m_observers;
};
Now, much more logic can be centrally added to this ObserverContainer, including calling all observers. The 'initiator' of the call only needs to create and fill in the notification structure.
Classes that want to inherit from multiple kinds of observers, need to do it like this:
class MyObserver : public IObserver<NotifyThis>, public IObserver<NotifyThat>
{
...
};
Which of these approaches (observers with multiple explicit arguments or with one struct argument) seems the best? Are there any advantages or disadvantages to either of these approaches?
EDIT: I looked a bit further to alternative approaches, and the Slot/Signal approach seems another good candidate. Are there any important disadvantages in Slot/Signal that I should know of?
Why not just do:
class IObserver {
// whatever is in common
};
class IDoThisObserver : public IObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
class IDoThatObserver : public IObserver
{
public:
void handlDoThat(double arg1) = 0;
};
?
Then you have:
class ObserverContainer
{
public:
void addObserver (IObserver* t) {m_observers.push_back(t);}
private:
std::list<IObserver*> m_observers;
};
The design with the struct argument is definitely better as it allows for generic code to be written in the ObserverContainer. It's generally a good design practice to replace longish argument lists with objects that encapsulate the arguments and this is a good example of the payoff. By creating a more general abstraction for your notify method (with the struct you're defining notify as a method that takes a chunk of "data" whereas with the arg list you're defining a method that takes two numbers) you allow yourself to write generic code that uses the method and doesn't have to concern itself with the exact composition of the passed in chunk of data.
Have you looked into Boost.Signals? Better than to reimplement the wheel.
As for Parameters: Calling an observer/slot should conceptionally be the same as if you would call an ordinary function. Most SignalSlots-Implementations allow multiple Parameters, so use it. And please use different signals for different observer types, then there is no need to pass around data in Variants.
Two Disadvantages of the Observer-Pattern/SignalSlots i have seen:
1) Program flow is difficult or even impossible to understand by looking only at the source.
2) Heavily dynamic programs with lots of Observers/SignalSlots may encounter a "delete this"
Everything aside, i like Observers/SignalSlots more than subclassing and thus high coupling.
I don't think either of your approaches would fit your requirement as is. However a little modification using a DataCarrier containing the dataset passed across all the observers wherein each observer would know what to read would do the trick. The sample code below might clear it (note i have not compiled)
enum Type {
NOTIFY_THIS,
NOTIFY_THAT
};
struct Data {
virtual Type getType() = 0;
};
struct NotifyThisData: public Data {
NotifyThisData(int _a, int _b):a(_a), b(_b) { }
int a,b;
Type getType() { return NOTIFY_THIS; }
};
struct NotifyThatData: public Data {
NotifyThatData(std::string _str):str(_str) { }
std::string str;
Type getType() { return NOTIFY_THAT; }
};
struct DataCarrier {
std::vector<Data*> m_TypeData;
};
class IObserver {
public:
virtual void handle(DataCarrier& data) = 0;
};
class NotifyThis: public virtual IObserver {
public:
virtual void handle(DataCarrier& data) {
vector<Data*>::iterator iter = find_if(data.m_TypeData.begin(), data.m_TypeData.end(), bind2nd(functor(), NOTIFY_THIS);
if (iter == data.m_TypeData.end())
return;
NotifyThisData* d = dynamic_cast<NotifyThisData*>(*iter);
std::cout << "NotifyThis a: " << d->a << " b: " << d->b << "\n";
}
};
class NotifyThat: public virtual IObserver {
public:
virtual void handle(DataCarrier& data) {
vector<Data*>::iterator iter = find_if(data.m_TypeData.begin(), data.m_TypeData.end(), bind2nd(functor(),NOTIFY_THAT);
if (iter == data.m_TypeData.end())
return;
NotifyThatData* d = dynamic_cast<NotifyThatData*>(*iter);
std::cout << "NotifyThat str: " << d->str << "\n";
}
};
class ObserverContainer
{
public:
void addObserver (IObserver* obs) {m_observers.push_back(obs);}
void notify(DataCarrier& d) {
for (unsigned i=0; i < m_observers.size(); ++i) {
m_observers[i]->handle(d);
}
}
private:
std::vector<IObserver*> m_observers;
};
class MyObserver: public NotifyThis, public NotifyThat {
public:
virtual void handle(DataCarrier& data) { std::cout << "In MyObserver Handle data\n"; }
};
int main() {
ObserverContainer container;
container.addObserver(new NotifyThis());
container.addObserver(new NotifyThat());
container.addObserver(new MyObserver());
DataCarrier d;
d.m_TypeData.push_back(new NotifyThisData(10, 20));
d.m_TypeData.push_back(new NotifyThatData("test"));
container.notify(d);
return 0;
}
This way u need to modify only the enum if u add a new structure.
Also u can use boost::shared_ptr to handle the mess of pointers.
I wouldn't get the syntax right so I'm just going to list the declarations to illustrate the structures. A generic Observer could be made to expect a parameter that is either subclassed to specific forms of your required parameters or is struct including a horizontal mapping of all primitive parameters that will be required by your Observers. Then the ObserverContainer could function as an AbstractFactory and each subclass of the ObserverContainer could be DoThatObserverFactory and DoThisObserverFactory. The factory would build an observer and assign a configuration to the observer to tell it which parameter to expect.
class AbstractObserverFactory {...};
class DoThatObserverFactory : AbstractObserverFactory {...};
class DoThisObserverFactory : AbstractObserverFactory {...};
class ObserverParam {...};
class DoThatObserverParam : ObserverParam {...};
class DoThisObserverParam : ObserverParam {...};
class Observer;
class DoThisObserver : public Observer
{
public:
void handlDoThis(DoThisObserverParam);
};

How to Elegantly convert switch+enum with polymorphism

I'm trying to replace simple enums with type classes.. that is, one class derived from a base for each type. So for example instead of:
enum E_BASE { EB_ALPHA, EB_BRAVO };
E_BASE message = someMessage();
switch (message)
{
case EB_ALPHA: applyAlpha();
case EB_BRAVO: applyBravo();
}
I want to do this:
Base* message = someMessage();
message->apply(this); // use polymorphism to determine what function to call.
I have seen many ways to do this which all seem less elegant even then the basic switch statement. Using dyanimc_cast, inheriting from a messageHandler class that needs to be updated every time a new message is added, using a container of function pointers, all seem to defeat the purpose of making code easier to maintain by replacing switches with polymorphism.
This is as close as I can get: (I use templates to avoid inheriting from an all-knowing handler interface)
class Base
{
public:
template<typename T> virtual void apply(T* sandbox) = 0;
};
class Alpha : public Base
{
public:
template<typename T> virtual void apply(T* sandbox)
{
sandbox->applyAlpha();
}
};
class Bravo : public Base
{
public:
template<typename T> virtual void apply(T* sandbox)
{
sandbox->applyBravo();
}
};
class Sandbox
{
public:
void run()
{
Base* alpha = new Alpha;
Base* bravo = new Bravo;
alpha->apply(this);
bravo->apply(this);
delete alpha;
delete bravo;
}
void applyAlpha() {
// cout << "Applying alpha\n";
}
void applyBravo() {
// cout << "Applying bravo\n";
}
};
Obviously, this doesn't compile but I'm hoping it gets my problem accross.
Well, after giving in to dynamic_cast and multiple inheritance, I came up with this thanks to Anthony Williams and jogear.net
class HandlerBase
{
public:
virtual ~HandlerBase() {}
};
template<typename T> class Handler : public virtual HandlerBase
{
public:
virtual void process(const T&)=0;
};
class MessageBase
{
public:
virtual void dispatch(HandlerBase* handler) = 0;
template<typename MessageType>
void dynamicDispatch(HandlerBase* handler, MessageType* self)
{
dynamic_cast<Handler<MessageType>&>(*handler).process(*self);
}
};
template<typename MessageType> class Message : public MessageBase
{
virtual void dispatch(HandlerBase* handler)
{
dynamicDispatch(handler, static_cast<MessageType*>(this));
}
};
class AlphaMessage : public Message<AlphaMessage>
{
};
class BravoMessage : public Message<BravoMessage>
{
};
class Sandbox : public Handler<AlphaMessage>, public Handler<BravoMessage>
{
public:
void run()
{
MessageBase* alpha = new AlphaMessage;
MessageBase* bravo = new BravoMessage;
alpha->dispatch(this);
bravo->dispatch(this);
delete alpha;
delete bravo;
}
virtual void process(const AlphaMessage&) {
// cout << "Applying alpha\n";
}
virtual void process(const BravoMessage&) {
// cout << "Applying bravo\n";
}
};
int main()
{
Sandbox().run();
return 0;
}
It looks like you are trying to find some sort of double-dispatch system. Look into the Visitor pattern or other multiple-dispatch systems.
Your Bravo and Alpha classes are actually closures... Too bad C++ does not support them directly.
You could use a member pointer to do this:
typedef void (Sandbox::*SandboxMethod)();
struct BrAlpha {
BrAlpha(SandboxMethod method) : method(method){}
void apply(Sandbox sb){sb->*method();}
};
BrAlpha alpha(&Sandbox::applyAlpha);
BrAlpha bravo(&Sandbox::applyBravo);
(syntax may not be exact, but you know hat I mean)
I don't necessarily have an answer for your design pattern issue (though Modern C++ Design has a lot to say about it), but I do want to address your switch vs inheritance comment.
The problem with that simple swtich statement is maintainability. If that switch statement were in 1 location, then it's probably about the same amount of typing to create classes and inherit, but that switch statement is still a ticking time-bomb awaiting yet another state added without adding a case for it. If you assert the default:, you'll catch it at run time - eventually, but that's very poor. If you setup a bunch of function pointers and compile time assert on the table's size, you're doing better, but that's another level deeper than the switch statement. And this all goes out the window as soon as you have a second place in the code that needs to check state.
It's just that much easier once you have your interface class setup to let the compiler handle all the junk code of switching on states internally. You add the class need not worry about any other code as long as you follow the interface.