Handling events raised from a lower level object - c++

I'm writing a C++ programm using GTK+3.0. Anyway, I think this question may apply to any framework that uses events / signals.
I have a container class, say containerClass and a child class, say childClass. A childClass object child is contained inside a containerClass object container.
The child object is written to modify properties of something. To this aim, it has GtkEntry, GtkButton and so on. When I click the "save button", an event is raised.
This event must be handled by the container object, because the container is interfaced with a database in someway.
Hereafter, you find the solution I'm using to do the job:
// Child class
class childClass {
void setClickHandler_External(void (*extFun)(string property), void *);
void (*clickHandler_External)(string, void *);
void *clickHandler_External_Data;
static void buttonClicked(GtkWidget *widget, void *data);
}
void childClass::setClickHandler_External(void (*extFun)(string), void *data) {
// Set the external event handler
clickHandler_External = extFun;
clickHandler_External_Data = data;
}
void childClass::buttonClicked(GtkWidget *widget, void *data) {
childClass *m = (childClass *)data;
// Call the external event handler
m->clickHandler_External(property, m->clickHandler_External_Data);
}
// Container Class
class containerClass {
childClass child;
static void clickHandler(string property, void *data);
}
containerClass::containerClass() {
// Set the event handler
child.setClickHandler_External((void(*)(string))&(this->clickHandler), (void *)this);
}
void containerClass::clickHandler(string property, void *data) {
// Event handler in the upper class
containerClass *m = (containerClass *)data;
//FINALLY, DO THE JOB WITH PROPERTY!!!
}
This works well and does the job. Anyway, I was wondering if there is a smarter and cleaner way to achieve the same aim, maybe without using pointers to static functions, or by defining some kind of pattern to be reused everytime I need to have the same mechanism.
Thanks in advance

Gtkmm uses the sigc++ library to take care of all of this for you. There is no need to write it yourself.
Documentation links:
Signals overview
Appendix with detailed information
So, in this case, I would use something like
button.signal_clicked().connect(sigc::mem_fun(container, &containerClass::clickHandler));
while making sure that containerClass::clickHander has the appropriate number of arguments.

My first suggestion would be to use use templates to improve the type safety of what you are doing:
template< class ParamType >
void childClass::setClickHandler_External(void (*extFun)(string, ParamType *),
ParamType *data)
{
// Set the external event handler
clickHandler_External = (void ()(string,void*))extFun;
clickHandler_External_Data = (void*)data;
}
Then you can simplify the containerClass implementation as such:
// Container Class
class containerClass {
childClass child;
static void clickHandler(string property, containerClass *data);
}
containerClass::containerClass() {
// Set the event handler
child.setClickHandler_External(&containerClass::clickHandler, this);
}
void containerClass::clickHandler(string property, containerClass *data) {
//FINALLY, DO THE JOB WITH PROPERTY!!!
}
While it's great that this cleans up the implementation, removing the explicit casting from all the container implementors, that's not really the point. The point is to prevent you from passing wrong pointers into setClickHandler_External, causing crashes on the back end when events get dispatched.
My next step would take us further from your implementation, but would require more details about what you are actually doing. Depending on your needs that would be looking into:
Inheritance: should containerClass derive from childClass? That would provide access to a virtual function table that we could override.
Functors: look at boost::function and boost::bind to implement functors, eliminating the intermediate static function call.
Lambda Functions: bleeding edge (C++11 or later), but may be a good fit for this kind of forwarding function.

Related

Pass argument to function taking parent class argument without casting argument to parent class

I am building a Boost state machine. My state has a pointer to its own backend (fsm) to process events. All events of my state machine are children of an MySatetMachineEvent class (with an example child like EventChild). State transitions are only defined for children like EventChild of MySTateMachineEvent.
To clean up my code I want to create a function processEvent(MySatetMachineEvent event) taking all possible events. This class should then call the process_event() function with the passed event.
For example:
processEvent(MyStateMachineEvent event)
{
fsm.process_event(event);
}
processEvent(EventCild());
should case a call of
fsm.process_event(EventChild());
Creating such a function causes the error that fsm.process_event() is called with an instance of MyStateMachineEvent. As written above there are no state transitions defined for this case.
This hinders my state machine from working in a proper manner, obviously.
So my question is if there is a way to pass any EventChild or other child of MyStateMachineEvent to my processEvent(MySTateMachineEvent event) function without casting the passed Object to MyStateMachineEvent.
I am aware of the solution to overlode my function like
processEvent(EventChild event) {
fsm.process_event(event);
}
This would cause may functions (with the exact same line of code inside) in my case, thus i am looking for a cleaner and more fancy solution.
You can use a function template:
template <typename Event>
void processEvent(Event event)
{
fsm.process_event(event);
}
Every instantiation will preserve the exact type of the event argument that was passed in.
Albeit I like Vittorio Romeo's template approach, it might not be suitable if you e. g. have some kind of event queue holding arbitrary events. A polymorphic approach could be more suitable then:
class MyStateMachineEvent
{
public:
virtual ~MyStateMachineEvent() { }
virtual void doOrGetSomething() = 0;
};
class EventChild : public MyStateMachineEvent
{
public:
void doOrGetSomething() override;
};
Now your processEvent function might accept a reference, just as would the fsm's variant as well:
void processEvent(MyStateMachineEvent& event)
{
fsm.processEvent(event);
}
void FSM::processEvent(MyStateMachineEvent& event)
{
// ...
event.doOrGetSomething();
// ...
}
And usage might look like this:
std::queue<std::unique_ptr<MyStateMachineEvent>> events;
events.emplace(new EventChild());
processEvent(**events.front());
events.pop();

Connecting Qt slots and signals from a C++98 interface with no Qt, STL or Boost

I am writing an audio rendering library that takes as input audio buffers, does some magic, then manage playback on a selected device. For this task, I decided to use Qt's QAudioOutput class.
I would like to allow the user to set callbacks when the state of the QAudioOutput object state changes (active, suspended, stopped and idle). I would connect these signals to a signal handler that would call the user-defined callbacks. However, I have the following restriction: no STL, no Qt, no Boost on the library header. I also need to stay compatible with C++98.
Right now, I have 2 solutions (with drawbacks) and I am looking to improve the design. My first solution was:
// library header
class AudioLibrary
{
typedef void ( *Callback )();
void setOnActiveCallback( Callback cb );
};
The problem with this solution is that the client can only pass static functions or non-capturing lambdas. This is too restrictive. Imagine a client who wants to do something as simple as re-enabling a button once playback finished. Not possible if the button is a member variable.
My second solution was that my interface would be an abstract class and contains pure virtual functions that would contain the desired behavior on state change. However, I am not sure this would be much fun for the client of the library...
Is there a cleaner and/or better solution that I ommited to think of?
This sounds like a C style callback.
class AudioLibrary
{
typedef void ( *Callback )( void * );
void setOnActiveCallback( Callback cb, void * context );
// Perhaps also include
template <typename Func>
void setOnActiveCallback( Func & f )
{
setOnActiveCallback( &Func::operator(), &f );
}
};
C-style callbacks without a means to pass context are completely utterly broken and your users will hate you for that. Don't do it. As soon as you have a intptr_t or void* typed context object, you can pass anything you wish to the callback, and quite efficiently at that. Yes, you can pass capturing lambdas, member methods, etc.
E.g.:
class AudioLibrary {
typedef void (*Callback)(void*);
void setOnActiveCallback(Callback cb, void * context);
};
Then:
static void functionCallback(void * context) {
auto f = reinterpret_cast<std::function<void()>*>(context);
f();
}
struct User {
AudoLibrary * m_audio;
std::function<void()> f_onActive{std::bind(&User::onActive, this)};
void onActive();
User(AudioLibrary * audio) : m_audio(audio) {
audio->setOnActiveCallback(functionCallback, &f_member);
}
};

How can I reduce coupling in my Event Bus implementation

In my application, I have several modules that don't fit an 'is-a' or 'has-a' relationship, but still need to communicate and pass data to each other. To try and loosely couple these modules, I've implemented an Event Bus class that handles message passing from 'event posters' to 'event listeners'.
Classes can implement IEventListener if they wish to register to receive certain events. Likewise, classes can call EventBus::postEvent() if they need to push an event out to the bus. When EventBus::update() is called EventBus processes the queue of scheduled messages and routes them to registered listeners.
EventBus.h
#pragma once
#include <queue>
#include <map>
#include <set>
#include <memory>
class IEvent
{
public:
static enum EventType
{
EV_ENEMY_DIED,
EV_ENEMY_SPAWNED,
EV_GAME_OVER
};
virtual ~IEvent() {};
virtual EventType getType() const = 0;
};
class IEventListener
{
public:
virtual void handleEvent(IEvent * const e) = 0;
};
class EventBus
{
public:
EventBus() {};
~EventBus() {};
void update();
void postEvent(std::unique_ptr<IEvent> &e);
void registerListener(IEvent::EventType t, IEventListener *l);
void removeListener(IEvent::EventType t, IEventListener *l);
private:
std::queue<std::unique_ptr<IEvent>> m_eventBus;
std::map<IEvent::EventType, std::set<IEventListener *>> m_routingTable;
};
EventBus.cpp
#include "EventBus.h"
using namespace std;
/**
* Gives the EventBus a chance to dispatch and route events
* Listener callbacks will be called from here
*/
void EventBus::update()
{
while (!m_eventBus.empty())
{
// Get the next event (e_local now owns the on-heap event object)
unique_ptr<IEvent> e_local(move(m_eventBus.front()));
m_eventBus.pop();
IEvent::EventType t = e_local->getType();
auto it = m_routingTable.find(t);
if (it != m_routingTable.end())
{
for (auto l : ((*it).second))
{
l->handleEvent(e_local.get());
}
}
}
}
/**
* Posts an event to the bus, for processing and dispatch later on
* NB: The event bus will takes ownership of the on-heap event here
*/
void EventBus::postEvent(unique_ptr<IEvent> &e)
{
// The EventBus now owns the object pointed to by e
m_eventBus.push(unique_ptr<IEvent>(move(e)));
}
/**
* Registers a listener against an event type
*/
void EventBus::registerListener(IEvent::EventType t, IEventListener *l)
{
// Add this listener entry
// If the routing table doesn't have an entry for t, std::map.operator[] will add one
// If the listener is alredy registered std::set.insert() won't do anything
m_routingTable[t].insert(l);
}
/**
* Removes a listener from the event routing table
*/
void EventBus::removeListener(IEvent::EventType t, IEventListener *l)
{
// Check if an entry for event t exists
auto keyIterator = m_routingTable.find(t);
if (keyIterator != m_routingTable.end())
{
// Remove the given listener if it exists in the set
m_routingTable[t].erase(l);
}
}
As you can see, in my current implementation, I create concrete IEvent implementations for every type of event I want to pass around. I did this so that each event can have custom data attached to it (a requirement for my situation). Unfortunately, this means my EventBus system has to know about all the users of the system, increasing the coupling between my EventBus class and the users of the class. Additionally, the IEvent interface needs to hold a list of all event types as an enum, which has the same problem (increased coupling).
Is there a way to modify this implementation so that EventBus can be totally generic (doesn't need to know about the users of the EventBus), and yet still allow me to pass custom data with each event? I looked into C++11 variadic template functions but couldn't figure out how to use them in this case.
As a side-question, am I using std::unique_ptr correctly here?
Question 1 "Is there a way to modify this implementation so that EventBus can be totally generic":
Short answer, yes.
Longer answer: There are many ways of accomplishing this. One is described here:
Both the producer and the consumer of the event needs to agree on the type/data but the EventBus itself does not need to know. One way of accomplishing this could be to use boost::signals2::signal<T> as the event type. This will give you a proven, flexible and type safe signal/slot implementation. What it will not provide, however, is the possibility to queue up slot callbacks and process them from the EventBus::update()-function.
But, that can also be remedied. By making the event type EventBus::postEvent() takes as a parameter be std::function<void()> and calling postEvent() like this:
boost::signals2::signal<int> signal;
...
eventbus.postEvent(boost::bind(signal, 42));
// note: we need to use boost::bind (not std::bind) for boost::signals to be happy
The EventBus will see a std::function<void()> and dispatch to the slot. The data (42 in this example) will be kept by the result of boost::bind and be used as the parameter when the slot is called.
Question 2 "Am I using std::unique_ptr correctly":
Almost. I would drop the reference of EventBus::postEvent making it:
void EventBus::postEvent(std::unique_ptr<IEvent> e);
By doing this, you force the caller to actively move the std::unique_ptr<IEvent> into the EventBus. This will make the user aware the EventBus takes ownership and also making it obvious to people reading the code what the intent is and how ownership is transferred.
CppCoreGuidelines R.32:
"Take a unique_ptr parameter to express that a function assumes ownership of a widget"

C++ system for passing events with inheritance hierarchy

I am currently programming an event passing system for a game in C++ and I thought it would be useful if the events inherited from each other in a logical way.
This means I could for example raise an event of type NukeExplosion, which derives from Explosion (which would probably derive from an empty base class Event) and it would get passed to all listeners to an event of type NukeExplosion, as well as the more generic Explosion.
So far I was able to come up with two possible solutions:
Doing a dynamic_cast on the event for each set of listeners to the same event type. If it succeeds, I can then pass the event to all the listeners in the set.
Adding a piece of code to each Event type which raises the event again, but with a more generic type. The event would then be passed to listeners using the result of the typeid operator in conjunction with a map of listeners.
I don't really like the second option, because it's error-prone, and requires me to write almost the same code in every event class.
The problem with the first option is that it might need to do a lot of dynamic_casts, and I would like to avoid that.
So, is there any other way which I haven't taken into accont, or is the first option the best I can do? Or should I completely drop the inheritance of events?
I came here with almost exactly this question. The problem is basically that C++ won't let a function like handle (ExplosionEvent *e) accept an argument e with static type Event * even when the dynamic type of e is ExplosionEvent *. It would be a nice feature to have, but I'm not quite sure what else would have to change in the language.
The Visitor pattern is the cleanest solution I can think of. The drawbacks are that it's verbose and that it may not be cheaper than dynamic_cast<>.
Main.hpp:
#include <iostream>
class Event;
class Handler;
#include "Event.hpp"
#include "Handler.hpp"
Event.hpp:
#ifndef EVENT_H
#define EVENT_H
class Event
{
public:
virtual void accept (Handler *handler) { }
};
class ExplosionEvent : public Event
{
void accept (Handler *handler);
};
#endif // !EVENT_H
Event.cpp:
#include "Main.hpp"
void
ExplosionEvent::accept (Handler *handler)
{
handler->handleExplosion (this);
}
Handler.hpp:
#ifndef HANDLER_H
#define HANDLER_H
class Handler
{
public:
void handle (Event *event) { event->accept (this); }
virtual void handleExplosion (ExplosionEvent *explosionEvent) { }
};
class ExplosionHandler : public Handler
{
void handleExplosion (ExplosionEvent *explosionEvent);
};
#endif // !HANDLER_H
Handler.cpp:
#include "Main.hpp"
void
ExplosionHandler::handleExplosion (ExplosionEvent *explosionEvent)
{
std::cout << "BOOM!" << std::endl;
}
Main.cpp:
#include "Main.hpp"
int
main (int argc, char *args)
{
Event *event = new ExplosionEvent;
Handler *handler = new ExplosionHandler;
handler->handle (event);
}
Compile and run:
$ g++ -o boom *.cpp
$ ./boom
BOOM!
$
Doing a dynamic cast for every listener will get really expensive for a large number of listeners so you probably will have to implement a map of typeid to listeners anyway.
My listener would have an HandleEvent which would take an Event object. This method would cast(with a static_cast) the base event to the event type it is expecting(it needs to trust the event dispatcher for the event registering mechanism).
I would also implement a method in the Event class which would return a new base event if valid because you might not want to send a base Event. This could be done with a macro but I have a feeling it could also be done with a template method although I haven't been able to make it work yet. The dispatcher would then get that base event before calling the event handlers and then call the handlers for the base event.

How to implement the observer pattern safely?

I'm implementing a mechanism similar to the observer design pattern for a multithreaded Tetris game. There is a Game class which contains a collection of EventHandler objects. If a class wants to register itself as a listener to a Game object it must inherit the Game::EventHandler class. On state change events a corresponing method is called on the EventHandler interface of each listener. This is what the code looks like:
class Game
{
public:
class EventHandler
{
public:
EventHandler();
virtual ~EventHandler();
virtual void onGameStateChanged(Game * inGame) = 0;
virtual void onLinesCleared(Game * inGame, int inLineCount) = 0;
private:
EventHandler(const EventHandler&);
EventHandler& operator=(const EventHandler&);
};
static void RegisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler);
static void UnregisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler);
typedef std::set<EventHandler*> EventHandlers;
EventHandlers mEventHandlers;
private:
typedef std::set<Game*> Instances;
static Instances sInstances;
};
void Game::RegisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler)
{
ScopedReaderAndWriter<Game> rwgame(inGame);
Game * game(rwgame.get());
if (sInstances.find(game) == sInstances.end())
{
LogWarning("Game::RegisterEventHandler: This game object does not exist!");
return;
}
game->mEventHandlers.insert(inEventHandler);
}
void Game::UnregisterEventHandler(ThreadSafe<Game> inGame, EventHandler * inEventHandler)
{
ScopedReaderAndWriter<Game> rwgame(inGame);
Game * game(rwgame.get());
if (sInstances.find(game) == sInstances.end())
{
LogWarning("Game::UnregisterEventHandler: The game object no longer exists!");
return;
}
game->mEventHandlers.erase(inEventHandler);
}
There are two problems that I often experience with this kind of pattern:
A listener object wants to unregister itself on an already deleted object resulting in a crash.
A event is fired to a listener that no longer exists. This happens most often in multithreaded code. Here's a typical scenario:
The game state changes in a worker thread. We want the notification to occur in the main thread.
The event is wrapped in a boost::function and sent as a PostMessage to the main thread.
A short time later this function object is processed by the main thread while the Game object is already deleted. The result is a crash.
My current workaround is the one that you can see in above code sample. I made the UnregisterEventHandler a static method which checks against a list of instances. This does help, but I find it a somewhat hackish solution.
Does anyone know of a set of guidelines on how to cleanly and safely implement notifier/listener system? Any advice on how to avoid the above pitfalls?
PS: If you need more information in order to answer this question you can find the relevant code online here: Game.h, Game.cpp, SimpleGame.h, SimpleGame.cpp, MainWindow.cpp.
The rule of thumb is that delete and new for an object should be near each other. E.g. in constructor and destructor or before and after a call where you use the object. So it's a bad practice to delete an object in another object when the latter one didn't create the former one.
I don't understand how you pack the events. It seems that you have to check whether the game is still alive before processing an event. Or you can use shared_ptr in events and other places to be sure that games are deleted last.
I write a lot of C++ code and needed to create an Observer for some game components I was working on. I needed something to distribute "start of frame", "user input", etc., as events in the game to interested parties. I had the same problem to consider...the firing of an event would lead to the destruction of another observer which may also subsequently fire. I need to handle this. I did not need to handle thread safety, but the design requirement I usually shoot for is to build something simple enough (API wise) that I can put in a few mutexes in the right place and the rest should take care of itself.
I also wanted it to be straight C++, not dependent on the platform or a specific technology (such as boost, Qt, etc.) because I often build and re-use components (and the ideas behind them) across different projects.
Here is the rough sketch of what I came up with as a solution:
The Observer is a singleton with keys (enumerated values, not strings) for Subjects to register interest in. Because it is a singleton, it always exists.
Each subject is derived from a common base class. The base class has an abstract virtual function Notify(...) which must be implemented in derived classes, and a destructor that removes it from the Observer (which it can always reach) when it is deleted.
Inside the Observer itself, if Detach(...) is called while a Notify(...) is in progress, any detached Subjects end up on a list.
When Notify(...) is called on the Observer, it creates a temporary copy of the Subject list. As it iterates over it, it compare it to the recently detached. If the target is not on it, Notify(...) is called on the target. Otherwise, it is skipped.
Notify(...) in the Observer also keeps track of the depth to handle cascading calls (A notifies B, C, D, and the D.Notify(...) triggers a Notify(...) call to E, etc.)
This is what the interface ended up looking like:
/*
The Notifier is a singleton implementation of the Subject/Observer design
pattern. Any class/instance which wishes to participate as an observer
of an event can derive from the Notified base class and register itself
with the Notiifer for enumerated events.
Notifier derived classes MUST implement the notify function, which has
a prototype of:
void Notify(const NOTIFIED_EVENT_TYPE_T& event)
This is a data object passed from the Notifier class. The structure
passed has a void* in it. There is no illusion of type safety here
and it is the responsibility of the user to ensure it is cast properly.
In most cases, it will be "NULL".
Classes derived from Notified do not need to deregister (though it may
be a good idea to do so) as the base class destrctor will attempt to
remove itself from the Notifier system automatically.
The event type is an enumeration and not a string as it is in many
"generic" notification systems. In practical use, this is for a closed
application where the messages will be known at compile time. This allows
us to increase the speed of the delivery by NOT having a
dictionary keyed lookup mechanism. Some loss of generality is implied
by this.
This class/system is NOT thread safe, but could be made so with some
mutex wrappers. It is safe to call Attach/Detach as a consequence
of calling Notify(...).
*/
class Notified;
class Notifier : public SingletonDynamic<Notifier>
{
public:
typedef enum
{
NE_MIN = 0,
NE_DEBUG_BUTTON_PRESSED = NE_MIN,
NE_DEBUG_LINE_DRAW_ADD_LINE_PIXELS,
NE_DEBUG_TOGGLE_VISIBILITY,
NE_DEBUG_MESSAGE,
NE_RESET_DRAW_CYCLE,
NE_VIEWPORT_CHANGED,
NE_MAX,
} NOTIFIED_EVENT_TYPE_T;
private:
typedef vector<NOTIFIED_EVENT_TYPE_T> NOTIFIED_EVENT_TYPE_VECTOR_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T> NOTIFIED_MAP_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T>::iterator NOTIFIED_MAP_ITER_T;
typedef vector<Notified*> NOTIFIED_VECTOR_T;
typedef vector<NOTIFIED_VECTOR_T> NOTIFIED_VECTOR_VECTOR_T;
NOTIFIED_MAP_T _notifiedMap;
NOTIFIED_VECTOR_VECTOR_T _notifiedVector;
NOTIFIED_MAP_ITER_T _mapIter;
// This vector keeps a temporary list of observers that have completely
// detached since the current "Notify(...)" operation began. This is
// to handle the problem where a Notified instance has called Detach(...)
// because of a Notify(...) call. The removed instance could be a dead
// pointer, so don't try to talk to it.
vector<Notified*> _detached;
int32 _notifyDepth;
void RemoveEvent(NOTIFIED_EVENT_TYPE_VECTOR_T& orgEventTypes, NOTIFIED_EVENT_TYPE_T eventType);
void RemoveNotified(NOTIFIED_VECTOR_T& orgNotified, Notified* observer);
public:
virtual void Reset();
virtual bool Init() { Reset(); return true; }
virtual void Shutdown() { Reset(); }
void Attach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for a specific event
void Detach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for ALL events
void Detach(Notified* observer);
/* The design of this interface is very specific. I could
* create a class to hold all the event data and then the
* method would just have take that object. But then I would
* have to search for every place in the code that created an
* object to be used and make sure it updated the passed in
* object when a member is added to it. This way, a break
* occurs at compile time that must be addressed.
*/
void Notify(NOTIFIED_EVENT_TYPE_T, const void* eventData = NULL);
/* Used for CPPUnit. Could create a Mock...maybe...but this seems
* like it will get the job done with minimal fuss. For now.
*/
// Return all events that this object is registered for.
vector<NOTIFIED_EVENT_TYPE_T> GetEvents(Notified* observer);
// Return all objects registered for this event.
vector<Notified*> GetNotified(NOTIFIED_EVENT_TYPE_T event);
};
/* This is the base class for anything that can receive notifications.
*/
class Notified
{
public:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const void* eventData) = 0;
virtual ~Notified();
};
typedef Notifier::NOTIFIED_EVENT_TYPE_T NOTIFIED_EVENT_TYPE_T;
NOTE: The Notified class has a single function, Notify(...) here. Because the void* is not type safe, I created other versions where notify looks like:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, int value);
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const string& str);
Corresponding Notify(...) methods were added to the Notifier itself. All these used a single function to get the "target list" then called the appropriate function on the targets. This works well and keeps the receiver from having to do ugly casts.
This seems to work well. The solution is posted on the web here along with the source code. This is a relatively new design, so any feedback is greatly appreciated.