Обратные вызовы в C++. Виталий Евгеньевич Ткаченко. Читать онлайн. Newlib. NEWLIB.NET

Автор: Виталий Евгеньевич Ткаченко
Издательство: ЛитРес: Самиздат
Серия:
Жанр произведения: Программирование
Год издания: 2020
isbn:
Скачать книгу
и недостатки реализации обратных вызовов с помощью указателя на метод – член класса приведены в Табл. 4.

      Табл. 4. Преимущества и недостатки реализации обратных вызовов с помощью указателя на метод-член класса.

      Гибкость. Управлять контекстом можно тремя способами, подобные возможности отсутствуют в других реализациях.

      Отсутствие трансляции контекста. Контекст транслировать не нужно, метод-член имеет полный доступ к содержимому класса.

      Сложность. Код получается довольно громоздким и запутанным.

      Тип класса должен объявляться в инициаторе. Здесь достаточно только предварительного объявления класса. Полное объявление класса в инициаторе делать необязательно и даже нежелательно, потому что логически это обработчик обратного вызова, то есть он относится к исполнителю и должен быть в нем реализован. Тем не менее, требование предварительного объявления класса ограничивает независимость исполнителя: он может использовать только те типы классов, которые были предварительно объявлены в инициаторе.

      Инициатор должен хранить указатель на метод и указатель на класс. Увеличивается расход памяти.

      2.4. Функциональный объект

      2.4.1. Концепция

      С точки зрения C++ функциональный объект – это класс, который имеет перегруженный оператор вызова функции7.

      Графическое изображение обратного вызова с помощью функционального объекта представлено на Рис. 14. Исполнитель реализуется в виде класса, код упаковывается в перегруженный оператор вызовы функции, в качестве контекста выступает экземпляр класса. При настройке экземпляр класса как аргумент сохраняется в инициаторе8. Инициатор осуществляет обратный вызов посредством вызова перегруженного оператора, передавая ему требуемую информацию. Контекст здесь передавать не нужно, поскольку внутри оператора доступно все содержимое класса.

      Рис. 14. Реализация обратного вызова с помощью функционального объекта.

      2.4.2. Инициатор

      Предварительно необходимо объявить функциональный объект (см. Листинг 15), потому что его объявление должен видеть как инициатор, так и исполнитель.

Листинг 15.Объявление функционального объекта

      class CallbackHandler

      {

      public:

        void operator() (int eventID) //This is an overloaded operator

        {

            //It will be called by server

        };

      };

      Реализация инициатора приведена в Листинг 16.

Листинг 16. Инициатор с функциональным объектом

      class Initiator  // (1)

      {

      public:

        void setup(const CallbackHandler& callback)  // (2)

        {

            callbackObject = callback;

        }

        void run()  // (3)

        {

            int eventID = 0;

            //Some actions

            callbackObject(eventID);  // (4)

        }

      private:

        CallbackHandler callbackObject;  // (5)

      };

      В строке 1 мы объявляется класс-инициатор. В строке 2 объявляется функция для настройки вызова, в которую передается ссылка на функциональный объект.


<p>7</p>

Другое название, которое встречается в литературе, – функтор.

<p>8</p>

В инициаторе хранится копия экземпляра класса. Не ссылка, не указатель, а именно копия. Из этого вытекает несколько важных следствий, которые будут рассмотрены далее.