Обратные вызовы в C++ | страница 45
Рис. 17. Стирание типов: а) исходное состояние; б) состояние после назначения нового типа аргумента
Реализация рассмотренной схемы представлена в Листинг 45.
>class UniArgument // (1)
>{
>private:
> class Callable // (2)
> {
> public:
> virtual void operator()(int) = 0; // (3)
> };
> std::unique_ptr
> template
> class CallableObject : public Callable // (5)
> {
> public:
> CallableObject(ArgType argument) : storedArgument(argument) { } // (6)
> void operator() (int value) override // (7)
> {
> storedArgument(value); // (8)
> }
> private:
> ArgType storedArgument; // (9)
> };
>public:
> void operator() (int value) // (10)
> {
> callablePointer->operator()(value); // (11)
> }
> template
> void operator = (ArgType argument) // (12)
> {
> callablePointer.reset(new CallableObject
> }
>};
В строке 1 объявлен класс, реализующий универсальный аргумент. В строке 2 объявлен класс, который будет использоваться в качестве базового.
В базовом классе перегружен оператор вызова функции 3. Оператор объявлен чисто виртуальным, чтобы опустить его реализацию. Предполагается, что этот оператор будет выполнять обратный вызов, но аргумента вызова здесь нет, он будет храниться в наследуемом классе. Таким образом, реализация смысла не имеет. Более того, если, допустим, нам понадобится, чтобы оператор возвращал результат, то в нем должна присутствовать команда return, и какое тогда возвращать значение?
В строке 4 объявлен указатель на базовый класс, объявленный в 2.
В строке 5 объявлен шаблонный класс, который будет хранить переданный аргумент и вызывать его. Переменная для хранения аргумента объявлена в строке 9, тип переменной задается параметром шаблона. Аргумент назначается в конструкторе 6. Также в этом классе переопределяется оператор вызова функции 7, в котором происходит обратный вызов 8 через сохраненный аргумент.