Рис. 11. Обратный вызов с указателем на статический метод класса


2.2.2. Инициатор

По своей сути статический метод класса – это обычная функция, ограниченная областью видимости класса. Поэтому реализация инициатора, представленная в Листинг 6, практически полностью повторяет реализацию для указателей на функцию, только в качестве контекста выступает указатель на экземпляр класса.

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

>class Executor;  //(1)


>class Initiator  // (2)

>{

>public:

>  using ptr_callback_static = void(*) (int, Executor*);                 // (3)


>  void setup(ptr_callback_static pPtrCallback, Executor* pContextData)  // (4)

>  {

>    ptrCallback = pPtrCallback; contextData = pContextData;             // (5)

>  }


>  void run()                           //  (6)

>  {

>    int eventID = 0;

>    //Some actions

>    ptrCallback(eventID, contextData);  // (7)

>  }


>private:

>  ptr_callback_static ptrCallback = nullptr;  // (8)

>  Executor* contextData = nullptr;            // (9)

>};


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

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

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

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

>class Executor                    // (1)

>{

>public:

>  Executor(Initiator* initiator)  // (2)

>  {

>    initiator->setup(callbackHandler, this);

>  }


>  static void callbackHandler(int eventID, Executor* executor)  // (3)

>  {

>    //It will be called by initiator

>    executor->onCallbackHandler(eventID);                       // (4)

>  }


>private:

>  void onCallbackHandler(int eventID)  // (5)

>  {

>    //Do what is necessary

>  }

>};


>int main() // (6)

>{

>  Initiator initiator;            // (7)

>  Executor executor(&initiator);  // (8)

>  initiator.run();                // (9)

>  //Wait finish

>}


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

В строке 3 объявлен статический метод как обработчик обратного вызова. Входными параметрами здесь являются информация вызова (в нашем случае это eventID) и указатель на контекст, в качестве которого выступает указатель на экземпляр класса. Внутри метода можно обращаться к содержимому класса, используя полученный указатель как квалификатор. Таким образом, прямо здесь можно реализовать код обработчика, а можно вызвать обычный (нестатический) метод класса (строка 4).

Далее, в строке 6 объявлена основная функция, в которой осуществляются все необходимые операции. В строке 7 объявлен класс-инициатор; в строке 8 объявлен класс- исполнитель, в конструктор передается указатель на инициатор; в строке 9 происходит запуск инициатора.

Особенностью реализации исполнителя с помощью указателя на статический метод является возможность работы с инициатором, предназначенным для указателей на функцию. В этом случае метод класса в качестве контекста должен принимать нетипизированный указатель с последующим приведением типов. Пример использования показан в Листинг 8, инициатор здесь используется из Листинг 1 п. 2.1.2.