Обратные вызовы в C++ | страница 44




>  // (9) Pointer to the static method

>  Initiator> initStaticMethod;

>  initStaticMethod.setup(CallbackConverter>(int, Executor*), Executor*>>(Executor::staticCallbackHandler, &executor));


>  // (14) Pointer to the class member method

>  Initiator> initMemberMethod;

>  initMemberMethod.setup(CallbackConverter>(&executor, &Executor::callbackHandler));

>}


Итак, как мы видим, для каждого типа аргумента обратного вызова нам приходится объявлять соответствующий инициатор. Может быть, можно сделать так, чтобы инициатор умел работать с различными типами аргументов? Для этого нужно спроектировать универсальный аргумент, чем мы и займемся в следующей главе.

4.5. Универсальный аргумент

4.5.1. Динамический полиморфизм

Для реализации универсального аргумента прежде всего необходимо обеспечить динамический полиморфизм, т. е. аргумент должен изменять свой тип в зависимости от задаваемого значения21.

Как решается указанная задача в объектно-ориентированном дизайне? Объявляется базовый абстрактный класс, в котором описывается интерфейс в виде набора чисто виртуальных методов. Новый тип создается путем создания наследуемого класса, в котором объявляются нужные переменные и переопределяются методы. При инициализации создается класс нужного типа, и он сохраняется в переменной – указателе на базовый класс. Мы будем использовать аналогичный подход, только наследуемые типы будут создаваться динамически, используя параметры шаблона. Указанная техника называется «стирание типов»: при назначении нового типа аргумента предыдущий сохраненный уничтожается, и его место занимает новый22.

Графическое изображение стирания типов изображено на Рис. 17. Рассмотрим начальное состояние а), показанное в верхней части рисунка. Имеется некоторый класс, назовем его UniArgument. В этом классе объявлен перегруженный оператор вызова функции 2. Также здесь имеется указатель 3 типа Callable*, который указывает на соответствующий экземпляр класса Callable. Класс Callable 4 объявлен внутри UniArgument и имеет виртуальный перегруженный оператор вызова функции с пустой реализацией.

Когда в UniArgument происходит вызов 1 перегруженного оператора 2, последний через указатель 3 вызывает виртуальный перегруженный оператор класса Callable.

В нижней части рисунка б) показано, как назначается новый тип. Объявляется перегруженный оператор присваивания