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

Callback Function C



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

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







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



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

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

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



#включают

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



intmainFn(charch[],int (*ptr)(int))

{

intid1знак равно 1;

intid2знак равно 2;

intкак правилознак равно (*ptr)(id2);

Стоимость<<'основная функция:'<<id1<<''<<ch<<''<<как правило<<' п';

возвращениеid1;

}


intcb(intотождествлять)

{

Стоимость<<'функция обратного вызова'<<' п';

возвращениеотождествлять;

}


intглавный()

{

int (*ptr)(int) знак равно &cb;

charнет[] знак равно 'а также';

mainFn(отец, cb);



возвращение 0;

}

Результат:





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

основная функция: 1 а также 2

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

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



intкак правилознак равно (*ptr)(id2);

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

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

int (*ptr)(int) знак равно &cb;

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

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

mainFn(отец, cb);

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

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

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

#включают

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



пустотаmainFn(пустота (*ptr)())

{

Стоимость<<'основная функция'<<' п';

(*ptr)();

}


пустотаcb()

{

Стоимость<<'функция обратного вызова'<<' п';

}


пустотаfn()

{

Стоимость<<'видимый'<<' п';

}


intглавный()

{

пустота (*ptr)() знак равно &cb;

mainFn(cb);

fn();



возвращение 0;

}

Результат:

основная функция

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

видимый

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

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

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

#включают

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



пустотаfn()

{

Стоимость<<'видимый'<<' п';

}


пустотаmainFn(пустота (*ptr)())

{

Стоимость<<'основная функция'<<' п';

fn();

(*ptr)();

}


пустотаcb()

{

Стоимость<<'функция обратного вызова'<<' п';

}


intглавный()

{

пустота (*ptr)() знак равно &cb;

mainFn(cb);



возвращение 0;

}

Результат:

основная функция

видимый

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

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

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

#включают

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



пустотаmainFn(пустота (*ptr)())

{

(*ptr)();

Стоимость<<'основная функция'<<' п';

}


пустотаcb()

{

Стоимость<<'функция обратного вызова'<<' п';

}


пустотаfn()

{

Стоимость<<'видимый'<<' п';

}


intглавный()

{

пустота (*ptr)() знак равно &cb;

mainFn(cb);

fn();



возвращение 0;

}

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

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

основная функция

видимый

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

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

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

тип вывода;

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

{

//заявления

}


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

{

//заявления

}

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

#включают

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

char *выход;


пустотаcb(charиз[])

{

выходзнак равноиз;

}



пустотаmainFn(charВход[],пустота (*ptr)(char[пятьдесят]))

{

(*ptr)(Вход);

Стоимость<<'основная функция'<<' п';

}


пустотаfn()

{

Стоимость<<'видимый'<<' п';

}


intглавный()

{

charВход[] знак равно 'функция обратного вызова';

пустота (*ptr)(char[]) знак равно &cb;

mainFn(вход, cb);

fn();

Стоимость<<выход<<' п';



возвращение 0;

}

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

основная функция

видимый

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

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

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

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

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

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

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

#включают

#включают

#включают

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

будущее<нить>выход;

строка cb(струнная полоса)

{

возвращениеполоса;

}



пустотаmainFn(строковый ввод)

{

выходзнак равноасинхронный(cb, ввод);

Стоимость<<'основная функция'<<' п';

}


пустотаfn()

{

Стоимость<<'видимый'<<' п';

}


intглавный()

{

строковый вводзнак равнонить('функция обратного вызова');

mainFn(Вход);

fn();

строка retзнак равновыход.получать(); // ожидает возврата обратного вызова, если необходимо

Стоимость<<Правильно<<' п';



возвращение 0;

}

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

Заключение

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

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