2012-03-06 9 views
0

Я хочу знать, где именно callback functions?Применение функции обратного вызова

И есть ли способ реализовать функцию обратного вызова (кроме использования указателя функции) в C/C++?

Пожалуйста, объясните следующую строку -

"A callback can be used as a simpler alternative to polymorphism and generic programming"

Благодарности

+0

Может быть дубликат http://stackoverflow.com/questions/142789/what-is-a-callback-in-c-and-how-are-they-implemented – Jay

+0

2 примера: [библиотека стандартной библиотеки C qsort] (http://pubs.opengroup.org/onlinepubs/009695399/functions/qsort.html) и [Асинхронный ввод-вывод] (http://en.wikipedia.org/wiki/Asynchronous_I/O#Callback_functions) - Я не буду вдаваться в подробности, поскольку у меня такое чувство, что это задание. – pmdj

+0

@Jay Я уже прошел через это. Я просил заявки не для реализации! Так же, как и Core Audio, мы говорим об этом! – Vikram

ответ

5

Я хочу знать, где на самом деле используются функции обратного вызова?

Два наиболее распространенные виды использования, чтобы позволить пользователю реализовать часть алгоритма (например, компараторы передаются Кассиопеян qsort и C++ 's std::sort разрешить сортировку любых типов), а также получать уведомления о внешних событиях (например, во многих асинхронных пользовательских интерфейсах и коммуникационных библиотеках, таких как Boost.Asio).

И есть ли способ реализовать функцию обратного вызова (кроме использования указателя функций) в C/C++?

Нет такого языка, как C/C++.

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

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

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

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

C++ 11 предлагает некоторые удобные новые способы обработки функторов. std::function - это полиморфный тип, который может представлять любую функцию, подобную функции, и является хорошим типом для обратного вызова, если вы не хотите создавать шаблоны над типом функции.std::bind и лямбда-выражения - это простые способы определения функтора из какой-либо произвольной части кода.

обратного вызова может быть использован в качестве более простой альтернативы полиморфизма и обобщенное программирование

из контекста, что не делает много смысла. Я предполагаю, что это означает, что если вы используете указатель функции для обратного вызова, вам не нужно определять какие-либо абстрактные интерфейсы или функторы. Некоторые могут считать это более простым, если они считают, что полиморфизм и общность сложны; однако он также приносит свои собственные осложнения, поскольку нет способа безопасного доступа к произвольным пользовательским данным для обратного вызова, как это бывает с методами C++.

1

Примером может служить qsort. Вы передаете функцию обратного вызова, чтобы определить порядок элементов.

Я не уверен, что обратные вызовы проще, чем полиморфизм, если вы не закодированы на C в течение 50 лет и никогда не работали с ООП. Полиморфизм является центральной концепцией ООП и связан не только с C++, тогда как не все языки ООП имеют указатели на функции.

Но это правда, в чистом C вы можете имитировать полиморфизм с помощью указателей функций.

+0

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

+0

@ RichardJ.RossIII: Правда, но в наши дни «создание целого класса как делегата» так же просто, как написание выражения лямбда - и проще, чем создание целой функции, являющейся делегатом. –

+0

@MikeSeymour «создание лямбды» в стандартном C/C++ невозможно, о чем идет речь. Вот почему я создал яблочные блоки, поскольку они действуют как анонимный делегат из C# по большей части, но являются указателем функции за кулисами. –

0

Я хочу знать, где на самом деле используются функции обратного вызова?

GUI programming. На платформе Windows, когда вы хотите сделать окно, вы передаете функцию обратного вызова в систему, которая управляет поведением окна. Конечно, высокоуровневые структуры скроют это поведение, но оно все еще здесь.

Multithreading, асинхронный IO, также, если вы хотите сделать что-то системным с помощью пользовательской функции (например, qsort).

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

0

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

  • Если внешний источник, вызывающий функцию, является аппаратным, вызываемая функция называется «службой обслуживания прерывания».
  • Если внешний источник является программным обеспечением, вызываемая функция называется «функция обратного вызова».

Например, вы найдете множество функций обратного вызова в программировании Windows. Каждое графическое окно имеет функцию обратного вызова «WindowProc», которая получает вызов от ОС для каждого действия, происходящего в окне. Затем программисту необходимо написать функцию обратного вызова и обработать события, которые они интересуют. События, которые им не интересны, передаются обработчику по умолчанию (или базовому классу, если хотите).

Если программист хочет, чтобы что-то особенное произошло при щелчке мышью по окну, они могут перезаписать поведение по умолчанию щелчка мыши, заменив поведение по умолчанию собственным кодом. Таким образом, вы достигаете полиморфизма, даже в программах на C.

Пример из программирования с Windows:

LRESULT CALLBACK WindowProc (HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) 
{ 
    switch(umsg) 
    { 
    case WM_LBUTTONDOWN: 

     do_something(); /* overwrite default behavior of a left mouse button click */ 

     break; /* break = and then execute the default behavior afterwards */ 

    case WM_RBUTTONDOWN: 

     do_something(); /* overwrite default behavior of a right mouse button click */ 

     return 0; /* overwrite the default behavior entirely */ 

    }  


    // execute default behavior for the event: 
    return DefWindowProc(hwnd, umsg, wparam, lparam); 
} 

break из оператора переключателя похож на обычное наследование: выполнить унаследованную функцию, а затем функцию базового класса. В то время как return 0; похож на полиморфизм/виртуальный объект, поскольку наследуемый объект полностью перезаписывает поведение по умолчанию.


Sidenote: Так как функция обратного вызова вызывается из внешнего источника, а не саму программу, некоторые из тупее компиляторы будут делать предположения о том, что функция не вызывается и, следовательно, выполнять опасные оптимизации.

Например, если глобальная переменная «флаг» была изменена из WindowProc выше, а код в main() полагается на «флаг», компилятор, возможно, оптимизирует код в main(), так как считает, что «флаг» был никогда не использовались нигде.

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

Смежные вопросы