Listing 5
// test application for messaging system

#include "Messaging.h"
#include <iostream>
#include <string>

using namespace std;

// some listener interface
struct MartianAlertListener
{
    virtual void martianLanded(const string &where) = 0;
};

// some other listener interface
struct NuclearPSListener
{
    virtual void itIsHot(int temp) = 0;
    virtual void itIsTooLate() = 0;
};

// a commong functionality of the normal person and
// the technician in the nuclear power station
class Person
{
public:
    Person(const string &name) : name_(name) {}
    string getName() const { return name_; }
private:
    string name_;
};

// a class representing the normal person
// normal person is interested in the MartianAlert events
class NormalPerson : public Person,
                     public MartianAlertListener
{
public:
    NormalPerson(const string &name)
        : Person(name) {}

    // here, the Person receives the notification
    virtual void martianLanded(const string &where)
    {
        cout << getName() << ": martian landed "
            << where << endl;
    }
};

// a context structure for MartianAlert events,
// holding the info considering the landing place
struct MartianContext
{
    string where_;
};

// the helper typedef
typedef
Messaging<MartianAlertListener, MartianContext>
MartianAlertSource;

// another class, representing a technician in
// the nuclear power station
// the technician is interested in
// the events related to his job
class Technician : public Person,
                   public NuclearPSListener
{
public:
    Technician(const string &name)
        : Person(name) {}

    void itIsHot(int temp)
    {
        cout << getName() << ": there is " << temp
            << " degrees in the reactor" << endl;
    }
    void itIsTooLate()
    {
        cout << getName() << ": BANG!" << endl;
    }
};

// a context structure for events in the power station,
// holding info considering:
// 1. what has happened
// 2. what is the temperature in the reactor
struct NuclearPSContext
{
    enum eWhat {it_is_hot, it_is_too_late} whathappened_;
    int temp_;
};

// the helper typedef
typedef
Messaging<NuclearPSListener, NuclearPSContext>
NuclearPSSource;


// the ultimate source of events
// note multiple inheritance
// (one for each listener type)
class EventSource : public MartianAlertSource,
                    public NuclearPSSource
{
public:
    // inherited from MartianAlertSource
    void dispatchEvent(MartianAlertListener *p,
                const MartianContext &context)
    {
        // just call the listener
        p->martianLanded(context.where_);
    }

    // inherited from NuclearPSSource
    void dispatchEvent(NuclearPSListener *p,
            const NuclearPSContext &context)
    {
        // we have a choice and parameters with some details
        if (context.whathappened_ ==
            NuclearPSContext::it_is_hot)
            p->itIsHot(context.temp_);
        else
            p->itIsTooLate();
    }

    // play a little with events
    void go()
    {
        // send a martian alert

        MartianContext ctx1;
        ctx1.where_ = "in the garden";

        // note: if this class inherits from
        // only one event source base,
        // the operator:: is not needed
        MartianAlertSource::raiseEvent(ctx1);

        // send a temperature report

        NuclearPSContext ctx2;
        ctx2.whathappened_ = NuclearPSContext::it_is_hot;
        ctx2.temp_ = 5000;
        NuclearPSSource::raiseEvent(ctx2);

        // send a "too late" event notification

        NuclearPSContext ctx3;
        ctx3.whathappened_ = NuclearPSContext::it_is_too_late;
        NuclearPSSource::raiseEvent(ctx3);
    }
};

int main()
{
    // these are object which will receive
    // event notifications:
    NormalPerson john("John");
    NormalPerson jenny("Jenny");
    NormalPerson mike("Mike");
    Technician tech1("technician 1");
    Technician tech2("technician 2");

    // this is a source of events
    EventSource source;

    // register objects as listeners in an event source
    // note: if an event source inherits from only one
    // event source base, the :: selectors are not needed
    source.MartianAlertSource::addListener(&john);
    source.MartianAlertSource::addListener(&jenny);
    source.MartianAlertSource::addListener(&mike);
    source.NuclearPSSource::addListener(&tech1);
    source.NuclearPSSource::addListener(&tech2);

    // play
    source.go();

    return 0;
}