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

Читать онлайн книгу Обратные вызовы в C++ - Виталий Евгеньевич Ткаченко страница 7

СКАЧАТЬ style="font-size:15px;">      Далее, в строке 4 объявлена основная функция, в которой осуществляются все необходимые операции. В строке 5 объявляются данные контекста; в строке 6 производится настройка обратного вызова, в функцию настройки передаются указатель на функцию-обработчик и указатель на контекст; в строке 7 инициатор запускается.

      Реализация исполнителя для случая, когда инициатор реализован в объектно-ориентированном дизайне, представлена в Листинг 4. Как видим, она очень похожа на предыдущую реализацию с той разницей, что мы объявляем экземпляр класса-инициатора (строка 5), и все вызовы осуществляем через вызов соответствующих методов класса.

Листинг 4. Исполнитель для инициатора в объектно-ориентированном дизайне

      struct СontextData // (1)

      {

        //some context data

      };

      void callbackHandler(int eventID, void* somePointer) // (2)

      {

        //It will be called by initiator

        СontextData* pContextData = static_cast<СontextData*>(somePointer); // (3) cast to context

      }

      int main() // (4)

      {

        Initiator  initiator;                             // (5)

        СontextData clientContext;                        // (6)

        initiator.setup(callbackHandler, &clientContext); // (7) callback setup

        initiator.run();                                  // (8) initiator has been run

        //Wait finish

      }

      2.1.4. Синхронный вызов

      Реализация инициатора для синхронного вызова приведена в Листинг 5. Как видим, для синхронных вызовов код значительно упрощается: нет необходимости хранить переменные, информация вызова и контекст передаются непосредственно в функцию.

Листинг 5. Инициатор для синхронного обратного вызова с указателем на функцию

      using ptr_callback  =  void(*) (int, void*);

      void run(ptr_callback ptrCallback, void* contextData = NULL)

      {

            int eventID = 0;

            //Some actions

            ptrCallback (eventID, contextData);

      }

      2.1.5. Преимущества и недостатки

      Достоинства и недостатки реализации обратных вызовов с помощью указателя на функцию представлены в Табл. 1.

      Табл. 1. Преимущества и недостатки обратных вызовов с указателем на функцию.

      Простая реализация. Как мы видели, инициатор реализуется достаточно просто: две переменных, синтаксис вызова функции через указатель очень похож на вызов обычной функции.

      Независимость инициатора и исполнителя. Любое изменение кода исполнителя никак не влияет на код инициатора, который при этом остается неизменным

      Совместим с кодом на языке C. В некоторых случаях приходится разрабатывать смешанный код, т. е. часть кода пишется C, а часть – на С++. Если код исполнителя написан на C++, и этот код должен быть вызван инициатором, написанным на C, то использование указателей на функцию является единственно доступным механизмом. 4

      Подходит для реализации любых API. Можно реализовать как С++, та и системные API. Для C++ API инициатор разрабатывается в виде набора СКАЧАТЬ



<p>4</p>

В качестве примера можно привести практику моделирования embedded-систем. В самом общем виде Embedded-системы представляют собой микроконтроллер, который встраивается в какое-либо устройство и выполняет функции управления, мониторинга и контроля. В силу определенных причин так сложилось, что ПО для управляющих контроллеров (такое ПО называют firmware) пишется на языке C. В процессе разработки подобных устройств часто используется моделирование, когда firmware запускается на обычном компьютере в имитационном окружении, а реальные аппаратные устройства заменяются их программными моделями. Модели и имитаторы обычно пишутся на языке C++, а firmware, как правило, написано на C – получается смешанный код.