C++ Event Handling

From Schmid.wiki
Jump to: navigation, search

Related to the Observer design pattern. Inspired from C# event handling.

Event Source

#pragma once

#include "eventreceiver.h"
#include <map>

class Event_source {
public:
    virtual ~Event_source() {}
    void raise(int event_id);
    void set_receiver(int event_id, Event_receiver *receiver);

private:
    std::multimap<int, Event_receiver *> event_receivers;
};

// call all event receivers for event_id
inline void
Event_source::raise(int event_id) {
    typedef std::multimap<int, Event_receiver *>::iterator MI;

    // find all receivers with event_id
    std::pair<MI, MI> receiver_range =
        event_receivers.equal_range(event_id);

    // invoke them
    for(MI p = receiver_range.first; p != receiver_range.second; ++p)
        (p->second)->handle(this, event_id);
}

inline void
Event_source::set_receiver(int event_id, Event_receiver *receiver) {

    event_receivers.insert(
            std::pair<int, Event_receiver *>(
               event_id, receiver));
}

Event Receiver Interface

#pragma once

class Event_source;

class Event_receiver {
public:
    virtual void handle(Event_source *source, int event_id) = 0;
};

Test

#include "eventsource.h"
#include "eventreceiver.h"

#include <iostream>

using namespace std;

class Ship : public Event_source {
public:
    typedef enum Event_type_enum { CRASH, SHOOT } Event_type;
    void crash() { raise(CRASH); }
    void shoot() { raise(SHOOT); }
};

class Enemy : public Ship { };

class Audio_system : public Event_receiver {
public:
    virtual void handle(Event_source *source, int event_id) {
        if     (dynamic_cast<Enemy *>(source)) cout << "Enemy: ";
        else if(dynamic_cast<Ship *> (source)) cout << "Ship: ";
        else cout << "U.F.O.: ";
        switch(event_id) {
            case Ship::CRASH: cout << "KABOOM" << endl; break;
            case Ship::SHOOT: cout << "ZAP"    << endl; break;
        }
    }
};

int main() {
    Ship ship;
    Enemy enemy;
    Audio_system audio_system;

    ship.set_receiver(Ship::CRASH, &audio_system);
    ship.set_receiver(Ship::SHOOT, &audio_system);
    enemy.set_receiver(Enemy::CRASH, &audio_system);
    enemy.set_receiver(Enemy::SHOOT, &audio_system);

    ship.shoot();
    enemy.crash();
}

Output:

Ship: ZAP
Enemy: KABOOM
Personal tools