Так уж исторически сложилось, что в языке С++ нет событий. Событием (event) является исходящий вызов (программисты на VB хорошо знакомы с ними) и в С++ их действительно нет. Иногда события путают с сообщениями (message), но это не верно. Сообщение это прямой вызов: например windows вызывает оконную процедуру для передачи собщения окну. Объект (система) вызывает функцию обькта(окна). Вызов происходит от объекта к объекту. В отличии от сообщения событие имеет другую механику. Объект инициирует событие и вызываются все объекты-обработчики. Т.е. от одного объекта к нескольким. Причем объект инициатор события может ничего не «знать» об его обработчиках, поэтому событие называют исходящим вызовом.
Раз уж в С++ события на уровне языка не поддерживаются, значит стоит организовать их на уровне библиотеки. Здесь приведена реализация такой библиотеки. В ней есть два класса signal и slot.
Итак, чтобы сделать какой нибудь класс источником события поместите в него переменную типа signal:
>struct EventRaiser { // источник события
> signal someEvent; // void – тип аргумента события
>};
А чтобы сделать класс обработчиком поместите в него переменную типа slot, функцию обработчик и свяжите slot с обработчиком:
>struct EventHandler { // обработчик события
> slot someHandler; // переходник
> void onEvent(void) {
> // функция обработчик события
> printf("event handled");
> }
> void connect (EventRaiser& er) {
> someHandler.init(er.someEvent, onEvent, this); // установим связь события с обработчиком
> }
>};
Так как эти объекты являются частью своих хозяев, не нужно заботится о времени жизни связи. Ее разрыв произойдет во время разрушения одного из них. Событие же инициируется вызвовом метода signal::raise:
>struct EventRaiser { // источник события
> signal someEvent; // void – тип аргумента события
> void someFunc() {
> someEvent.raise(); // инициация события
> }
>};
В примере создаются два класса обработчик и инициатор события, устанавливается связь между ними и иллюстрируется обработка события в нескольких объектах одновременно:
>#include "stdafx.h"
>#include "sigslot.h"
>struct EventRaiser {
>// источник события
> signal event; // const char* – тип аргумента. может быть void
> void raise(const char *eventName) {
> printf("raising %s event\n", eventName);
> event.raise(eventName);
> }
>} g_Raiser; // глобальный объект
>struct EventHandler { // обработчик события
> const char *color;
> slot handler; // переходник
> void onEvent(const char *eventName) { // обработчик события
> printf("\t%s event handled in %s object\n", eventName, color);
> }
> EventHandler(const char *clr): color(clr) {
> handler.init(g_Raiser.event, onEvent, this); // установим связь
> }
>};
>int main(int argc, _TCHAR* argv[]) {
> EventHandler red("Red");
> g_Raiser.raise("Small"); // событие обработается в red
> {
> {
> EventHandler blue("Blue");
> g_Raiser.raise("Big"); // событие обработается в red и blue
> }
> EventHandler green("Green");
> g_Raiser.raise("Medium"); // событие обработается в red и green.
> // объект blue уничтожен, связь разорвана
> }
> return 0;
>}
signal – cобытие (детали реализации опущены)
>template // Arg – тип аргумента функции обработчика
>class signal {
>public:
> // Инициировать событие
> void raise(
> Arg arg // Арумент arg будет передан в обработчики события
> );
>};
slot – переходник для обработки события в классе-обработчике (детали реализации опущены)
>class slot {
>public:
> // установить связь с событием и обработчиком
> template <
> class Owner, // класс-обработчик
> class Arg // Тип аргумента события.
> >
> void init(
> signal&sig, // событие
> void (Owner::*mpfn)(Arg), // функция обработчик
> Owner *This // обьект обработчик
> );
> // установить связь с событием и обработчиком для случая signal
> template <
> class Owner // класс-обработчик
> >
> void init(
> signal&sig, // событие
> void (Owner::*mpfn)(), // функция обработчик
> Owner *This // обьект обработчик
> );
> // разорвать связь
> void clear();
>};
Весь код находится в файле sigslot.h
>#ifndef _SIGSLOT_h_
>#define _SIGSLOT_h_
>// sigslot.h – autor Kluev Alexander [email protected]
>template
>class signal;
>class slot {
> friend class signal_base;
> slot *_prev;
> slot *_next;
> struct Thunk {};
> typedef void (Thunk::*Func)();
> Thunk *_trg;
> Func _mfn;
>public:
> slot(): _trg(0), _mfn(0), _prev(0), _next(0) {}
> ~slot() {clear();}
>public:
> void clear() {
> if (_next) _next->_prev = _prev;
> if (_prev) _prev->_next = _next;
> _prev = _next = 0;
> }
> template
> void init(signal&sig, void (Owner::*mpfn)(Arg), Owner *This) {
> clear();
> _trg = (Thunk*)This;
> _mfn = (Func)mpfn;
> sig._add(*this);
> }
> template
> void init(signal&sig, void (Owner::*mpfn)(), Owner *This) {
> clear();
> _trg = (Thunk*)This;
> _mfn = (Func)mpfn; sig._add(*this);
> }
>private:
> template
> void _call(Arg a) {
> typedef void (Thunk::*XFunc)(Arg);
> XFunc f = (XFunc)_mfn;
> (_trg->*f)(a);
> }
> void _call() {
> (_trg->*_mfn)();
> }
>};
>class signal_base {
>protected:
> friend class slot;
> slot _head;
> void _add(slot&s) {