Виталий Евгеньевич Ткаченко

Обратные вызовы в C++


Скачать книгу

Указатель на метод-член класса

      2.3.1. Концепция

      В предыдущей главе мы рассматривали использование указателя на статический метод класса, в который в качестве контекста передавали указатель на экземпляр класса. А почему бы нам напрямую не вызвать метод-член класса, минуя прослойку в виде статического метода, из которого вызывается метод-член класса? Для этого нам понадобятся указатель на класс и указатель на метод.

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

      Рис. 12. Реализация обратного вызова с помощью указателя на метод-член класса

      2.3.2. Инициатор

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

Листинг 10. Инициатор с указателем на метод-член класса

      class Executor;  // (1)

      class Initiator  // (2)

      {

      public:

        using ptr_callback_method = void(Executor::*)(int);  // (3)

        void setup(Executor* argCallbackClass, ptr_callback_method argCallbackMethod)    // (4)

        {

            ptrCallbackClass = argCallbackClass; ptrCallbackMethod = argCallbackMethod;  // (5)

        }

        void run()  // (6)

        {

            int eventID = 0;

            //Some actions

            (ptrCallbackClass->*ptrCallbackMethod)(eventID);  // (7)

        }

      private:

        Executor* ptrCallbackClass = nullptr;             // (8)

        ptr_callback_method ptrCallbackMethod = nullptr;  // (9)

      };

      В строке 1 делается предварительное объявление типа класса исполнителя. В строке 2 объявляется класс-инициатор, в строке 3 объявляется тип указателя для класса-исполнителя. В строке 4 объявляется функция для настройки указателей, соответствующие переменные (указатель на метод класса и указатель на экземпляр класса) объявлены в строках 8 и 9. В строке 6 объявлена функция запуска, внутри этой функции в строке 7 через соответствующий указатель производится вызов метода класса.

      2.3.3. Исполнитель

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

Листинг 11. Исполнитель с указателем на метод-член класса

      class Executor                       // (1)

      {

      public:

        void callbackHandler(int eventID)  // (2)

        {

            //It will be called by initiator

        }

      };

      int main()                                                 // (3)

      {

        Initiator initiator;                                     // (4)

        Executor executor;                                       // (5)

        initiator.setup(&executor, &Executor::callbackHandler);  // (6)

        initiator.run();                                         // (7)

      }

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