Типобезопасные обратные вызовы в C++

ОГЛАВЛЕНИЕ

В данной статье представлен класс, который добавляет типобезопасные обратные вызовы C++ в проекты.

•    Скачать исходники - 32.39 Кб
•    Скачать документацию - 33.08 Кб

Обсуждаемый класс добавляет типобезопасные обратные вызовы C++ в проекты. Его свойства заключаются в следующем:
•    Любую функцию в любом классе можно вызвать откуда угодно в любом другом классе.
•    Можно передать от 0 до 5 аргументов любого типа функции обратного вызова и задать любой тип возвращаемой переменной.
•    Обратный вызов можно передать в качестве аргумента любой функции.
•    Оптимизирован для высокой скорости.
•    Размер кода менее 1 Кб, не нужны дополнительные библиотеки.
•    Не зависит от платформы: работает на Windows, Linux, Mac, и т.д.
•    Был испытан в Visual Studio 6.0, 7.0, 7.1 и 8.0 (= Visual Studio 6, вплоть до .NET 2005).
•    Новое в версии 3.0 (октябрь 2007): класс также поддерживает обратные вызовы статических функций и функций внутри виртуально производных классов.

Введение

В C++ простого адреса функции недостаточно для определения обратного вызова, как в старом C. В C++ каждый экземпляр класса хранит переменные класса в своей собственной области памяти. Указатель this указывает на эту область переменных. При каждом вызове любой функции C++ указатель this невидимо передается функции и в дополнение к аргументам функции. Microsoft Visual Studio 6 использует регистр процессора ECX для передачи указателя this, тогда как нормальные аргументы функции проталкиваются в стек. Чтобы использовать обратные вызовы, скопируйте файлы Callback.h и PreProcessor.h в проект и #include "Callback.h".

Зачем использовать обратные вызовы?

Допустим, написан планировщик, реагирующий на определенные события путем выполнения соответствующих действий. События могут быть любыми, например, прибытие данных, ввод данных пользователем или таймеры, а действия являются выполнением любого кода. Планировщик содержит в дополнительном потоке бесконечный цикл, ждущий события. В Windows можно использовать функцию API WaitForMultipleObjects(), возвращающую индекс сигнализированного события. Планировщик выглядит следующим образом:

Пример кода, сопровождающий данную статью, использует обратные вызовы для сортировки списка разными функциями сортировки обратного вызова. Заметьте, что благодаря сигналам и слотам не нужно писать собственную функцию RegisterCallback()! Более подробно читайте в части 2 данной серии статей.

Определение обратных вызовов

В callback.h есть два класса: cCall и cCallGen. Происходящее внутри этих классов весьма сложно, поэтому здесь объясняется только применение. cCall определяется как:

cCall <_ReturnType, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5>

Можно использовать функции обратного вызова, принимающие 0, 1, 2, 3, 4 или 5 аргументов. Если нужно больше 5 аргументов, классы обратного вызова с легкостью расширяются. Однако рекомендуется передавать более 5 аргументов в виде структуры, чтобы код легче читался.

Допустим, надо осуществить обратный вызов следующей функции:

int cMyApplication::Calculate(float Factor, bool Flag, char* Name)
{
    ......
}

Для этой функции можно создать соответствующий обратный вызов:

cCall <int, float, bool, char*> i_CallbackCalculate;

Первый аргумент шаблона (int) всегда используется для определения типа возвращаемой переменной. Следующие аргументы шаблона (float, bool, char*) являются типами аргументов, передаваемых функции обратного вызова.

Чтобы определить обратный вызов для следующей функции без аргументов, возвращающей void,

void cMyApplication::Print()
{
    ......
}

надо написать:

cCall <void> i_CallbackPrint;

Присваивание обратных вызовов

Обратные вызовы могут присваиваться друг другу с помощью operator=, но из-за типобезопасности этих обратных вызовов следующее приводит к ошибке компилятора:

i_CallbackCalculate = i_CallbackPrint;  // ошибка
i_CallbackCalculate типа int function(float, bool, char*) нельзя присвоить i_CallbackPrint типа void function(void).
Читайте также:
  • Встраивание Python в C/C++: первая часть
    • Скачать исходные файлы - 5.23Кб• Скачать демонстрационный проект - 80.6 Кб Введение Статья "Встраивание Python в многопоточные приложения C/C++" (Linux Journal) вдохновила на более глубокое освещение темы встраивания Python. Эта статья написана с двумя целями:1. Она написана для программистов,...
  • Как экспортировать классы C++ из DLL
    •    Скачать исходники - 11.1 Кб Введение Динамически подключаемые библиотеки (DLL) являются составной частью платформы Windows с самого ее начала. DLL позволяют инкапсулировать часть функционала в автономном модуле с точным списком функций C, доступных внешним пользователям. В 1980-е годы, когд...
  • Декомпиляция и вызов функции по адресу
    •    Скачать демо - 75.92 Кб•    Скачать исходный код - 8.36 Кб Необходимые инструменты Эта статья использует отладчик (OllyDbg можно бесплатно скачать тут) и инжектор DLL Winject (бесплатно скачивается через интернет и включен в callbin.zip). Нужен компилятор C++ для компиляции кода для DLL. Ко...
  • Написание приложений Win32 с помощью одних классов C++ (часть 4)
    • Скачать проект и демо - 97.7 Кб Добавленные возможности Макросы NOTIFY_xxx_HANDLER Есть макросы карты сообщений типа ATL, применяемые для отправки сообщений WM_NOTIFY. Благодаря их улучшению они принимают дополнительный параметр "type". Новая форма - GE_NOTIFY_xxx_TYPEDHANDLER( ... , func, t...
  • Написание приложений Win32 с помощью одних классов C++ (часть 3)
    • Скачать проект и демо - 97.7 Кб Введение Изначально это не задумывалось как третья часть главной статьи. Почему? Потому что при разработке стыковочного каркаса был сделан вывод, что при достижении определенной зрелости кода потребуется общая переделка. Во-первых, чтобы исправить ряд ошибок и ...