Итак, я склонен не согласиться с Ури, немного.
Если вы реализуете шаблон Observer, вам нужно иметь возможность сказать:
«Когда объект X выполняет Y, я хочу выполнить код Z».
Использование подхода, основанного исключительно на абстрактном классе, не лучший способ сделать это. Требование отдельного класса (особенно в C ++) для каждого обработчика событий является излишним. Если вы пришли с Java, вот как они все делают. Однако у Java есть 2 функции, которые делают это только немного раздражающим: анонимный класс и классы-члены «экземпляра». Это позволяет вам определить несколько обработчиков для нескольких событий в одном классе. Вы должны добавить к методам префикс "class {", но вы можете сделать это.
C ++ не имеет ни анонимных классов, ни классов-экземпляров. Это делает использование абстрактного класса для событий гораздо более громоздким, если у вас есть несколько обработчиков, которым нужно совместно использовать состояние. Вы должны сделать то же самое, что и генерация замыканий вручную, что может очень быстро раздражать.
.NET использует делегаты для обработки событий, которые в основном являются указателями на безопасные функции типов. Они делают код для обработки событий очень простым. В отличие от указателей на функции в C ++, делегат объединяет указатели на функции-члены и статические указатели на функции. По сути, он может каррировать параметр «this» любой функции-члена, оставляя указатели на функции, которые выглядят как статические указатели на функции. Это означает, что тип объекта, обрабатывающего событие, не является частью события «интерфейс». Это делает его очень гибким.
Вы не можете сделать это напрямую, используя указатели на функции-члены C ++, потому что тип «this» в конечном итоге является частью типа указателя на функцию, что ограничивает ваши обработчики только появлением в текущем классе.
Лучшее решение для C ++ - это гибрид между ними. Вам нужен универсальный интерфейс, подобный следующему:
class EventHandler
{
public:
virtual void Handle() = 0;
};
А затем реализация функций-членов, подобных этой
template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:
MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
{
}
void Handle()
{
(m_pThis->*m_pFunc)();
}
private:
T* m_pThis;
void (T::*m_pFunc)();
};
template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
return new MemberFuncEventHandler<T>(pThis, pFunc);
}
Вы также можете аналогичным образом определить класс обработчика для статических методов. Тогда вы можете просто сделать такие вещи:
Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...