Достоинства и недостатки реализации обратных вызовов с помощью указателя на функцию представлены в Табл. 1.
Табл. 1. Преимущества и недостатки обратных вызовов с указателем на функцию
2.2. Указатель на статический метод класса
2.2.1. Концепция
Графическое изображение обратного вызова с помощью указателя на статический метод класса представлено на Рис. 11. Исполнитель реализуется в виде класса, код упаковывается в статический метод класса, в качестве контекста выступает указатель на экземпляр класса. При настройке указатель на статический метод как аргумент и указатель на класс как контекст сохраняются в инициаторе. Инициатор осуществляет обратный вызов посредством вызова метода, передавая ему требуемую информацию и контекст – указатель на класс.
Рис. 11. Обратный вызов с указателем на статический метод класса
2.2.2. Инициатор
По своей сути статический метод класса – это обычная функция, ограниченная областью видимости класса. Поэтому реализация инициатора, представленная в Листинг 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.
class Executor // (1)
{
public:
Executor(Initiator* initiator) // (2)
{
initiator->setup(callbackHandler, this);
}
static void callbackHandler(int eventID, Executor* executor) // (3)
{