C ++

Функция обратного вызова в C ++

Функция обратного вызова в C ++

Функция обратного вызова - это функция, которая является аргументом, а не параметром в другой функции. Вторую функцию можно назвать основной функцией. Итак, задействованы две функции: основная функция и сама функция обратного вызова. В списке параметров основной функции присутствует объявление функции обратного вызова без ее определения, как и объявления объекта без присваивания. Основная функция вызывается с аргументами (в main ()). Одним из аргументов в вызове основной функции является эффективное определение функции обратного вызова. В C ++ этот аргумент является ссылкой на определение функции обратного вызова; это не настоящее определение. Сама функция обратного вызова фактически вызывается в определении основной функции.

Базовая функция обратного вызова в C ++ не гарантирует асинхронного поведения в программе.  Асинхронное поведение - реальное преимущество схемы функции обратного вызова. В схеме асинхронной функции обратного вызова результат основной функции должен быть получен для программы до того, как будет получен результат функции обратного вызова. Это возможно сделать в C ++; однако в C ++ есть библиотека под названием future, чтобы гарантировать поведение схемы функции асинхронного обратного вызова.

В этой статье объясняется базовая схема функции обратного вызова. Многое на чистом C++. Что касается обратного вызова, также объясняется базовое поведение будущей библиотеки. Для понимания этой статьи необходимы базовые знания C ++ и его указателей.

Содержание статьи

Схема базовой функции обратного вызова

Схема функции обратного вызова требует основной функции и самой функции обратного вызова. Объявление функции обратного вызова является частью списка параметров основной функции. Определение функции обратного вызова указывается в вызове функции основной функции. Функция обратного вызова фактически вызывается в определении основной функции. Следующая программа иллюстрирует это:

#включать
используя пространство имен std;
int принципалFn (char ch [], int (* ptr) (int))

int id1 = 1;
int id2 = 2;
int idr = (* ptr) (идентификатор2);
cout<<"principal function: "<return id1;

int cb (int ID)

cout<<"callback function"<<'\n';
вернуть идентификатор;

int main ()

интервал (* ptr) (интервал) = &cb;
char cha [] = "и";
mainFn (cha, cb);
возврат 0;

Результат:

функция обратного вызова
основная функция: 1 и 2

Основная функция идентифицируется с помощью PrincipalFn (). Функция обратного вызова идентифицируется cb (). Функция обратного вызова определяется вне основной функции, но фактически вызывается внутри основной функции.

Обратите внимание на объявление функции обратного вызова в качестве параметра в списке параметров объявления основной функции. Объявление функции обратного вызова - «int (* ptr) (int)». Обратите внимание на выражение функции обратного вызова, как и на вызов функции, в определении основной функции; здесь передается любой аргумент для вызова функции обратного вызова. Заявление для этого вызова функции:

int idr = (* ptr) (идентификатор2);

Где id2 - аргумент. ptr - это часть параметра, указатель, который будет связан со ссылкой на функцию обратного вызова в функции main ().

Обратите внимание на выражение:

интервал (* ptr) (интервал) = &cb;

В функции main (), которая связывает объявление (без определения) функции обратного вызова с именем определения той же функции обратного вызова.

Основная функция вызывается в функции main () как:

mainFn (cha, cb);

Где cha - строка, а cb - имя функции обратного вызова без каких-либо ее аргументов.

Синхронное поведение функции обратного вызова

Рассмотрим следующую программу:

#включать
используя пространство имен std;
недействительный принципFn (void (* ptr) ())

cout<<"principal function"<<'\n';
(* ptr) ();

void cb ()

cout<<"callback function"<<'\n';

void fn ()

cout<<"seen"<<'\n';

int main ()

пусто (* ptr) () = &cb;
PrincipalFn (cb);
fn ();
возврат 0;

Результат:

основная функция
функция обратного вызова
видимый

Здесь есть новая функция. Все, что делает новая функция, - это отображение вывода «видно». В функции main () вызывается основная функция, затем вызывается новая функция fn (). Выходные данные показывают, что был выполнен код для основной функции, затем был выполнен код для функции обратного вызова и, наконец, для функции fn () была выполнена. Это синхронное (однопоточное) поведение.

Если бы это было асинхронное поведение, когда три сегмента кода вызываются по порядку, может быть выполнен первый сегмент кода, за которым вместо этого следует выполнение третьего сегмента кода, прежде чем будет выполнен второй сегмент кода.

Что ж, функцию fn () можно вызвать из определения основной функции, а не из функции main (), следующим образом:

#включать
используя пространство имен std;
void fn ()

cout<<"seen"<<'\n';

недействительный принципFn (void (* ptr) ())

cout<<"principal function"<<'\n';
fn ();
(* ptr) ();

void cb ()

cout<<"callback function"<<'\n';

int main ()

пусто (* ptr) () = &cb;
PrincipalFn (cb);
возврат 0;

Результат:

основная функция
видимый
функция обратного вызова

Это имитация асинхронного поведения. Это не асинхронное поведение. Это все еще синхронное поведение.

Кроме того, порядок выполнения сегмента кода основной функции и сегмента кода функции обратного вызова можно поменять местами в определении основной функции. Следующая программа иллюстрирует это:

#включать
используя пространство имен std;
 
недействительный принципалFn (void (* ptr) ())

(* ptr) ();
cout<<"principal function"<<'\n';

void cb ()

cout<<"callback function"<<'\n';

void fn ()

cout<<"seen"<<'\n';

int main ()

пусто (* ptr) () = &cb;
PrincipalFn (cb);
fn ();
возврат 0;

Выход сейчас,

функция обратного вызова
основная функция
видимый

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

Асинхронное поведение с функцией обратного вызова

Псевдокод для базовой схемы асинхронной функции обратного вызова:

тип вывода;
type cb (тип вывода)

//заявления

тип PrincipalFn (тип ввода, тип cb (тип вывода))

//заявления

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

#включать
используя пространство имен std;
char * output;
void cb (char out [])

output = out;

void PrincipalFn (char input [], void (* ptr) (char [50]))

(* ptr) (ввод);
cout<<"principal function"<<'\n';

void fn ()

cout<<"seen"<<'\n';

int main ()

char input [] = "функция обратного вызова";
void (* ptr) (char []) = &cb;
PrincipalFn (ввод, cb);
fn ();
cout<возврат 0;

Вывод программы:

основная функция
видимый
функция обратного вызова

В этом конкретном коде выходные и входные данные совпадают. Результат третьего вызова функции в функции main () был отображен перед результатом функции обратного вызова. Функция обратного вызова выполнила, завершила и присвоила свой результат (значение) переменной output, что позволило программе продолжить работу без ее вмешательства. В функции main () вывод функции обратного вызова использовался (читался и отображался), когда это было необходимо, что приводило к асинхронному поведению для всей схемы.

Это однопоточный способ получить асинхронное поведение функции обратного вызова с чистым C++.

Основы использования будущей библиотеки

Идея схемы асинхронной функции обратного вызова заключается в том, что основная функция возвращается до того, как функция обратного вызова возвращает. Это было сделано косвенно и эффективно в приведенном выше коде.

Обратите внимание на приведенный выше код, что функция обратного вызова получает основной ввод для кода и производит основной вывод для кода. В будущей библиотеке C ++ будет функция sync (). Первым аргументом этой функции является ссылка на функцию обратного вызова; второй аргумент - это вход в функцию обратного вызова. Функция sync () возвращается, не дожидаясь завершения выполнения функции обратного вызова, но позволяет функции обратного вызова завершиться. Это обеспечивает асинхронное поведение. Пока функция обратного вызова продолжает выполняться, поскольку функция sync () уже вернулась, операторы под ней продолжают выполняться. Это похоже на идеальное асинхронное поведение.

Вышеупомянутая программа была переписана ниже с учетом будущей библиотеки и ее функции sync ():

#включать
#включать
#включать
используя пространство имен std;
будущее выход;
строка cb (строка полосы)

return stri;

void PrincipalFn (строковый ввод)

output = async (cb, input);
cout<<"principal function"<<'\n';

void fn ()

cout<<"seen"<<'\n';

int main ()

строка input = строка ("функция обратного вызова");
PrincipalFn (ввод);
fn ();
строка ret = вывод.получать(); // ожидает возврата обратного вызова, если необходимо
cout<возврат 0;

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

Заключение

Функция обратного вызова - это функция, которая является аргументом, а не параметром в другой функции. Схема функции обратного вызова требует основной функции и самой функции обратного вызова. Объявление функции обратного вызова является частью списка параметров основной функции. Определение функции обратного вызова указывается в вызове функции основной функции (в main ()). Функция обратного вызова фактически вызывается в определении основной функции.

Схема функции обратного вызова не обязательно является асинхронной. Чтобы быть уверенным, что схема функции обратного вызова является асинхронной, сделайте основной ввод в код, ввод для функции обратного вызова; сделать основной вывод кода выводом функции обратного вызова; сохранить вывод функции обратного вызова в переменной или структуре данных. В функции main () после вызова основной функции выполнить другие операторы приложения. Когда требуется вывод функции обратного вызова, в функции main () используйте (прочтите и отобразите) его здесь, а затем.

Установите последнюю версию игры OpenRA Strategy в Ubuntu Linux
OpenRA - это игровой движок Libre / Free Real Time Strategy, воссоздающий ранние игры Westwood, такие как классическая Command & Conquer: Red Alert. Р...
Установите последнюю версию эмулятора Dolphin для Gamecube и Wii в Linux
Эмулятор Dolphin позволяет вам играть в выбранные вами игры Gamecube и Wii на персональных компьютерах (ПК) Linux. Являясь свободно доступным игровым...
Как использовать чит-движок GameConqueror в Linux
В статье содержится руководство по использованию чит-движка GameConqueror в Linux. Многие пользователи, играющие в игры на Windows, часто используют п...