Я проверил это в Интернете, и у меня есть небольшой опыт, поэтому я пришел поделиться и обсудить.
SECTION 1
Перезвони
Функция обратного вызова — это концепция, о которой время от времени можно услышать.Например, функция WinProc, встречающаяся в программировании Windows API, — это функция, которую мы пишем и которая вызывается операционной системой. Теперь нам нужно документировать эту проблему медленно и подробно.
Библиотеки и пользователи
Прежде чем начать, давайте сначала представим сценарий, в котором крупная компания-разработчик программного обеспечения разрабатывает набор программных библиотек для использования пользователями. В этом предложении появляются две противоположности, однасофтверная компания,одинПользователь. Очевидно, что компании-разработчики программного обеспечения сильны, и что делает их сильными, так это то, что они умны. Пожалуйста, посмотрите на изображение ниже:
Разработчики библиотек являются провайдерами, они не знают, что хотят делать пользователи, а разработчики библиотек не знают информации о пользователях, потому что люди с обеих сторон никогда не видели друг друга, как один человек в США и один человек в Китае. Самое умное в них то, что даже если они не знают, как работает пользователь, они могут использовать общий метод для решения проблемы пользователя. Другими словами, разработчик библиотеки может адаптироваться независимо от того, как пользователь борется с изменениями. В этом и заключается магия проблемы, конечно, для достижения такого эффекта должно быть какое-то правило, которым можно управлять.
правило
Теперь давайте поговорим о правилах. Правила легче понять. Это ограничения, достигнутые двумя сторонами. Например, два человека, A и B, A сказал B, пока вы даете мне пластиковый мяч, я могу его покрасить. Ограничения здесьпластиковый мяч(Конечно, для того, чтобы упростить проблему, ограничения здесь являются относительно общие и не строгие), в это время, если B дает ему хрустальный шар или автомобиль, она не будет работать, потому что ограничения были превышены. Поэтому самоочевидно, что разработчики библиотеки могут адаптироваться к различным изменениям пользователей, потому что они также дают пользователям определенные ограничения, которые являются адаптациями под ограничениями.
Никаких секретов под кодом
Следующий фрагмент кода прекрасно объясняет вышеуказанную проблему:
#include <stdio.h>
typedef int student_id;
typedef int student_age;
typedef struct _Student{
student_id id;
student_age age;
}Student;
//Переопределение типа: тип указателя функции
typedef bool (*pFun)(Student, Student);
//-----------------------------------------------
//Метод пузырьковой сортировки: можно сортировать по возрасту или идентификатору, реализован с той же функцией
//-----------------------------------------------
void sort(Student stu[],const int num,pFun fun)
{
Student temp;
for(int i = 0; i < num; ++i)
{
for(int j = 0; j < num - i -1; ++j)
{
if((*fun)(stu[j],stu[j+1]))
{
temp = stu[j];
stu[j] = stu[j+1];
stu[j+1] = temp;
}
}
}
}
//-----------------------------------------------
//функция обратного вызова: сравнить возраст
//-----------------------------------------------
bool CompareAge(Student stu1,Student stu2)
{
// Измените порядок с большого на маленький или с маленького на большой, просто переверните его.
if(stu1.age < stu2.age)
return true;
return false;
}
//-----------------------------------------------
//функция обратного вызова: сравнить идентификатор
//-----------------------------------------------
bool CompareId(Student stu1,Student stu2)
{
// Измените порядок с большого на маленький или с маленького на большой, просто переверните его.
if(stu1.id < stu2.id)
return true;
return false;
}
int main()
{
Student stu[] = {
{1103,24},
{1102,23},
{1104,22},
{1107,25},
{1105,21}};
pFun fun = CompareAge;
int size = sizeof(stu)/sizeof(Student);
sort(stu,size,fun);
for(int i = 0; i < size; ++i){
printf("%d %d\n",stu[i].id,stu[i].age);
}
return 0;
}
Через код мы должны указать, кто является поставщиком библиотеки, а кто пользователем:
sort(...)путьКукайПри условии, что он записан в файл только из-за проблемы с симуляцией Мы можем представить, что он хранится в статической библиотеке lib, так что он имеет с ней границу.
Разработчик библиотеки предоставляет нам для вызова метод sort(...) Формальный параметр также включает указатель на функцию, который должен вызвать функцию, написанную пользователем, то есть функцию обратного вызова. поэтому он обеспечиваетправило, то есть каков формальный параметр этой функции обратного вызова и каково возвращаемое значение.Если пользователь ничего не знает о формальных параметрах и возвращаемом значении этой функции обратного вызова и пишет функцию по своему желанию, может ли метод сортировки принять его? Очевидно нет.
Так как же пользователь узнает формальные параметры и возвращаемое значение функции обратного вызова и другую информацию? Разработчик библиотеки сообщит, или в его документации будут инструкции, так же как и функция WinProc(), предоставляемая при разработке оконных программ оконным API, формальные параметры в ней должны быть точно такими же. (Это место будет связано с интерфейсом)
Что обратно?
По приведенному выше коду мы знаем, что разработчик библиотеки предоставляет метод, а затем формальный параметр имеет указатель на функцию, ожидая, пока пользователь напишет, а затем вызовет ее, и вызовет эту функцию в своей реализации.С точки зрения разработчика библиотеки, можно резюмировать одним предложением: разработчик библиотеки вызывает функцию пользователя (функция обратного вызова).
Теперь переместим перспективу наПозиция функции обратного вызоваС точки зрения, это называется. Но в то же время у него тоже есть параметры, а передаваемые параметры — это данные, предоставленные разработчиком библиотеки.Здесь можно резюмировать еще одно предложение: callback-функция вызывает данные разработчика библиотеки.
Это"назад"Это означает, что вы звоните мне, а я звоню вам, обе стороны звонят друг другу.
В чем смысл функции обратного вызова?
Согласно вышеприведенному анализу обнаруживается, что функция обратного вызова несложна для понимания.Я думаю, что ключевым моментом является четкое разграничение, кто является разработчиком библиотеки (также называемым провайдером или вызывающим абонентом), кто является пользователем, а кто является пользователем.функцияЧеткое разделение является наиболее важным.
SECTION 2
tip1
Вы представляете, что часть вашей функции передается кому-то другому. Вам не нужно беспокоиться о том, как это реализовано, ваша функция имеет полную функцию, но некоторые функции можно настроить самостоятельно, см. for_each в stl
tip2
Проще говоря, пользователь является реализатором, и разработчик должен вызывать функцию A(), но для того, чтобы функция A() была универсальной, функция cbB(), предоставленная разработчиком, должна вызываться в соответствии с к пожеланиям разработчика, где cbB() дляПерезвони. в программировании виндовсПерезвониЭто очень универсально.
SECTION 3
Функция обратного вызова — это функция, вызываемая через указатель функции: указатель функции (адрес) передается в качестве параметра другой функции, и когда этот указатель используется для вызова функции, на которую он указывает, он называется функцией обратного вызова. Функция обратного вызова не вызывается непосредственно реализатором функции, а вызывается другой стороной, когда происходит определенное событие или условие, чтобы отреагировать на событие или условие.
С точки зрения непрофессионала: вызовите метод C в классе B в классе A, а затем класс B, в свою очередь, вызовет метод D в классе A, тогда D является функцией обратного вызова.
Например:
Мы относимся к классу А как к личности и называем его маленьким А, когда мы относимся к классу В как к личности, мы называем его маленьким В;
Тогда процесс использования callback-функции D можно понять следующим образом:
Сяо А столкнулся с проблемой в процессе разработки, и эту проблему может решить только Сяо Б, поэтому Сяо А нашел Сяо Б и попросил его о помощи, но поскольку он не был знаком с Сяо Б, он принес визитку. После того, как Сяо А объяснил Сяо Б проблему, с которой он столкнулся, случилось так, что Сяо Б был занят другими делами, поэтому Сяо Б сначала взял визитную карточку Сяо А и сказал Сяо А вернуться и ждать новостей. Поскольку эта проблема не решена, разработка не может быть продолжена, поэтому Сяо А, который вернулся и ждал новостей, должен был сначала заняться другими делами. Через какое-то время Сяо Б был занят своей работой и решил проблемы Сяо А. Он нашел номер телефона на визитной карточке Сяо А и набрал его, сказав Сяо А, что проблема решена (Сяо Б просто проследил за визитной карточкой и поставить Решение сообщается маленькому А, и его не волнует, как решение, данное им самим, будет использовано в маленьком А). После того, как Сяо А положил трубку, он продолжает разработку, используя решение, которое дал ему Сяо Б.
В двух словах: Сяо А взял визитную карточку D и нашел Сяо Б через маршрут С, чтобы попросить его о помощи. Сяо А, сказал он ему через визитную карточку D. Малый решение.
который:
Класс A вызывает метод C в классе B, а D используется как указатель на функцию в качестве параметра метода C (Маленький A приносит визитную карточку D, чтобы найти Little B через C, чтобы попросить его о помощи)
Класс B не может быть обработан немедленно, поэтому сначала отметьте функцию обратного вызова (получите визитную карточку)
В какой-то момент в будущем, когда будет выполнено условие триггера (после решения проблемы)
Передайте информацию обратно в класс A через функцию обратного вызова D (сообщите результат через визитную карточку)
Вот пример, иллюстрирующий описанный выше процесс (см. пояснения в примечаниях):
- #include
- typedef void (*Fun)(int); // определить тип указателя функции
- Fun p = NULL; // использовать Fun определить переменную p , который указывает на возвращаемое значение с пустым параметром как int Функция
- void caller(Fun pCallback)
- {
- p = pCallback;
- // Достигнув определенного условия, передайте визитную карточку (указатель функции p ), возвращает результат
- int result = 1;
- (*p)(result);
- }
- void callback(int a) // Перезвони
- {
- std::cout << "callback result = " << a << std::endl;
- }
- int main(int argc, char* argv[])
- {
- caller(callback);
- getchar();
- return 0;
- }