};
int main() // (3)
{
Initiator initiator; // (4)
Executor executor; // (5)
initiator.setup(&executor, &Executor::callbackHandler); // (6)
initiator.run(); // (7)
}
В строке 1 объявляется класс-исполнитель. В строке 2 объявлен метод класса, который будет выполнять функцию обработчика обратного вызова. В указанный метод передается информация вызова (в нашем случае это eventID). В строке 3 объявлена основная функция, в которой осуществляются все необходимые операции. В строке 4 объявлен класс-инициатор, в строке 5 объявлен класс-исполнитель. В строке 6 осуществляется настройка обратного вызова, в строке 7 производится запуск инициатора.
2.3.4. Управление контекстом
Рассматриваемая реализация позволяет осуществлять управление контекстом тремя способами: настройка экземпляра класса-исполнителя, настройка указателя на метод, переопределение виртуальных функций. Это приводит к интересным эффектам.
Пусть у нас будут объявления классов-исполнителей с наследованием, как показано в Листинг 12. Графически иерархия наследования изображена на Рис. 13.
Листинг 12. Классы-исполнители с наследованием
class Executor
{
public:
virtual void callbackHandler1(int eventID);
virtual void callbackHandler2(int eventID);
};
class Executor1: public Executor
{
public:
void callbackHandler1(int eventID) override;
};
class Executor2: public Executor
{
public:
void callbackHandler2(int eventID) override;
};
class Executor3: public Executor1, public Executor2
{
};
Рис. 13. Иерархия наследования классов-исполнителей.
Итак, будем назначать различные указатели на экземпляры классов и методы-члены, как показано в Листинг 13.
Листинг 13. Настройка указателей на классы и методы
int main()
{
Initiator initiator;
Executor executor;
Executor1 executor1;
Executor2 executor2;
Executor3 executor3;
initiator.setup(&executor, &Executor::callbackHandler1); // (1)
initiator.setup(&executor, &Executor::callbackHandler2); // (2)
initiator.setup(&executor1, &Executor::callbackHandler1); // (3)
initiator.setup(&executor1, &Executor::callbackHandler2); // (4)
initiator.setup(&executor2, &Executor::callbackHandler1); // (5)
initiator.setup(&executor2, &Executor::callbackHandler2); // (6)
//initiator.setup(&executor3, &Executor::callbackHandler1); //Incorrect, base class is ambiguous // (7)
//initiator.setup(&executor3, &Executor::callbackHandler2); //Incorrect, base class is ambiguous // (8)