Обратные вызовы в C++ | страница 9



Интерфейсы системных API должны объявляться в стиле языка C, т. е. в них должны использоваться функции с фиксированным числом параметров и простые структуры данных, такие, как числа, символы, указатели и структуры. Это связано с тем, что такие объявления следуют стандартным соглашениям операционной системы, в силу чего любая программа, независимо от используемого языка программирования (даже написанная на ассемблере), может использовать указанный API. Однако из-за требования описания интерфейсов в стиле C на реализацию обратных вызовов накладываются ограничения, которые будут рассматриваться в соответствующих главах.

1.5. Итоги

Обратный вызов – это паттерн, в котором какой-либо исполняемый код как аргумент передается в другой код, при этом ожидается, что через сохраненный аргумент исполняемый код будет запущен в нужный момент времени. Основные классы задач, решаемые с помощью обратных вызовов, следующие: запрос данных; вычисления по запросу; перебор элементов; уведомления о событиях.

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

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

Обратные вызовы часто используются в системных и C++ API. При использовании в системных API на реализацию обратных вызовов накладываются ограничения.

Рассмотрев общую концепцию, приступим к обзору способов реализации обратных вызовов.

2. Реализация обратных вызовов

2.1. Указатель на функцию

2.1.1. Концепция

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


Рис. 10. Обратный вызов с указателем на функцию


2.1.2. Инициатор

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

Листинг 1.Иинициатор с указателем на функцию

>typedef void(*ptr_callback) (int eventID, void* pContextData);  // (1)