Мне сложно увидеть полезность указателей на функции. Я предполагаю, что в некоторых случаях это может быть полезно (в конце концов, они существуют), но я не могу придумать случая, когда лучше или неизбежно использовать указатель на функцию.
Не могли бы вы привести пример правильного использования указателей на функции (на C или C ++)?
Ответы:
Большинство примеров сводятся к обратным вызовам : вы вызываете функцию,
f()
передавая адрес другой функцииg()
, иf()
вызываетеg()
какую-то конкретную задачу. Если вместо этого вы передадитеf()
адресh()
, то вместо этогоf()
перезвонитh()
.По сути, это способ параметризации функции: некоторая часть ее поведения жестко не закодирована
f()
, а встроена в функцию обратного вызова. Вызывающие абоненты могутf()
вести себя по-разному, передавая разные функции обратного вызова. Классический вариант взятqsort()
из стандартной библиотеки C, в которой критерий сортировки используется как указатель на функцию сравнения.В C ++ это часто делается с помощью объектов функций (также называемых функторами). Это объекты, которые перегружают оператор вызова функции, поэтому вы можете вызывать их, как если бы они были функцией. Пример:
Идея заключается в том, что, в отличие от указателя на функцию, объект функции может нести не только алгоритм, но и данные:
Еще одно преимущество состоит в том, что иногда проще встроить вызовы объектов функций, чем вызовы через указатели функций. По этой причине сортировка в C ++ иногда выполняется быстрее, чем в C.
источник
Ну, я обычно использую их (профессионально) в таблицах переходов (см. Также этот вопрос на StackOverflow ).
Таблицы переходов обычно (но не исключительно) используются в конечных автоматах для управления данными. Вместо вложенного переключателя / корпуса
вы можете создать двумерный массив указателей на функции и просто вызвать
handleEvent[state][event]
источник
Примеры:
источник
std::sort
«scomp
параметр как стратегия«Классическим» примером полезности указателей на функции является
qsort()
функция библиотеки C , которая реализует быструю сортировку. Чтобы быть универсальным для любых структур данных, которые может придумать пользователь, требуется пара пустых указателей на сортируемые данные и указатель на функцию, которая знает, как сравнивать два элемента этих структур данных. Это позволяет нам создать нашу функцию выбора для задания и фактически даже позволяет выбирать функцию сравнения во время выполнения, например, для сортировки по возрастанию или убыванию.источник
Согласитесь со всем вышеперечисленным, плюс .... Когда вы загружаете dll динамически во время выполнения, вам потребуются указатели на функции для вызова функций.
источник
Я собираюсь пойти против течения здесь.
В C указатели на функции - единственный способ реализовать настройку, потому что нет объектно-ориентированного программирования.
В C ++ для достижения одного и того же результата можно использовать указатели на функции или функторы (объекты функций).
Функторы имеют ряд преимуществ перед необработанными указателями на функции в связи с их объектной природой, а именно:
operator()
lambda
иbind
)Я лично предпочитаю функторы указателям на функции (несмотря на шаблонный код), в основном потому, что синтаксис для указателей на функции может легко запутаться (из Учебника по указателям на функции ):
Единственный раз, когда я видел, как указатели на функции используются там, где функторы не могут, был в Boost.Spirit. Они полностью злоупотребили синтаксисом, чтобы передать произвольное количество параметров как один параметр шаблона.
Но поскольку вариативные шаблоны и лямбды не за горами, я не уверен, что мы будем долго использовать указатели на функции в чистом коде C ++.
источник
bind
илиfunction
указатели на функции. Это как сказать, что мы не используем указатели в C ++, потому что мы используем интеллектуальные указатели. Во всяком случае, я придираюсь.В C классическим использованием является функция qsort , где четвертым параметром является указатель на функцию, используемую для выполнения упорядочивания в сортировке. В C ++ для такого рода вещей обычно используются функторы (объекты, похожие на функции).
источник
Недавно я использовал указатели на функции, чтобы создать уровень абстракции.
У меня есть программа, написанная на чистом C, которая работает во встроенных системах. Он поддерживает несколько вариантов оборудования. В зависимости от оборудования, на котором я работаю, ему необходимо вызывать разные версии некоторых функций.
Во время инициализации программа определяет, на каком оборудовании она работает, и заполняет указатели функций. Все подпрограммы более высокого уровня в программе просто вызывают функции, на которые ссылаются указатели. Я могу добавить поддержку новых вариантов оборудования, не затрагивая процедуры более высокого уровня.
Раньше я использовал операторы switch / case для выбора правильных версий функций, но это стало непрактичным, поскольку программа росла для поддержки все большего количества вариантов оборудования. Мне приходилось добавлять операторы case повсюду.
Я также пробовал использовать промежуточные функциональные уровни, чтобы выяснить, какую функцию использовать, но они не очень помогли. Мне все еще приходилось обновлять операторы case в нескольких местах, когда мы добавляли новый вариант. С указателями функций мне нужно изменить только функцию инициализации.
источник
Как сказал Ричард выше, указатели функций в Windows обычно ссылаются на какой-либо адрес, в котором хранится функция.
При программировании
C language
на платформе Windows вы в основном загружаете какой-то файл DLL в основную память (используяLoadLibrary
), а для использования функций, хранящихся в DLL, вам необходимо создать указатели функций и указать на этот адрес (используяGetProcAddress
).Ссылки:
LoadLibrary
GetProcAddress
источник
Указатели функций могут использоваться в C для создания интерфейса для программирования. В зависимости от конкретной функциональности, необходимой во время выполнения, указателю функции может быть назначена другая реализация.
источник
Я использовал их в основном для ОТВЕТОВ: когда вам нужно сохранить информацию о функции для последующего вызова .
Допустим, вы пишете Bomberman. Через 5 секунд после того, как человек сбросит бомбу, она должна взорваться (вызовите
explode()
функцию).Теперь есть 2 способа сделать это. Один из способов - «исследовать» все бомбы на экране, чтобы увидеть, готовы ли они взорваться в основном цикле.
Другой способ - прикрепить обратный вызов к вашей системе часов. Когда бомба закладывается, вы добавляете обратный вызов, чтобы он вызвал bomb.explode (), когда придет время .
Здесь
callback.function()
может быть любая функция , потому что это указатель на функцию.источник
Использование указателя функции
Для динамического вызова функции на основе пользовательского ввода. В этом случае создав карту строки и указателя на функцию.
Таким образом, мы использовали указатель на функцию в нашей фактической балансовой единице. Вы можете написать n номеров функций и вызывать их с помощью этого метода.
ВЫВОД:
источник
Другая точка зрения, помимо других хороших ответов здесь:
В C вы используете только указатели на функции, а не (напрямую) функции.
Я имею в виду, что вы пишете функции, но не можете манипулировать функциями. Не существует представления функции как таковой, которую вы могли бы использовать во время выполнения. Вы даже не можете назвать «функцию». Когда вы пишете:
на самом деле вы говорите «выполнить вызов
my_function
указателя с указанным аргументом». Вы делаете вызов через указатель функции. Этот переход на указатель функции означает, что следующие команды эквивалентны предыдущему вызову функции:и так далее (спасибо @LuuVinhPhuc).
Итак, вы уже используете указатели на функции в качестве значений . Очевидно, вы захотите иметь переменные для этих значений - и здесь могут быть задействованы все другие виды использования: полиморфизм / настройка (как в qsort), обратные вызовы, таблицы переходов и т. Д.
В C ++ все немного сложнее, так как у нас есть лямбды, объекты с
operator()
и дажеstd::function
класс, но принцип все тот же.источник
(&my_function)(my_arg)
,(*my_function)(my_arg)
,(**my_function)(my_arg)
,(&**my_function)(my_arg)
,(***my_function)(my_arg)
... , потому что функции распадаются на указатели на функцииДля языков OO - для выполнения полиморфных вызовов за кулисами (я полагаю, что до некоторой степени это также верно для C).
Более того, они очень полезны для внедрения другого поведения в другую функцию (foo) во время выполнения. Это делает функцию foo функцией высшего порядка. Помимо гибкости, это делает код foo более читабельным, так как позволяет вытащить из него дополнительную логику «if-else».
Он позволяет использовать множество других полезных вещей в Python, таких как генераторы, замыкания и т. Д.
источник
Я широко использую указатели на функции для эмуляции микропроцессоров с однобайтовыми кодами операций. Массив из 256 указателей на функции - естественный способ реализовать это.
источник
Одно из применений указателя на функцию может заключаться в том, что мы, возможно, не захотим изменять код, в котором вызывается функция (что означает, что вызов может быть условным, и при разных условиях нам нужно выполнять другой вид обработки). Здесь указатели на функции очень удобны, поскольку нам не нужно изменять код в том месте, где функция вызывается. Мы просто вызываем функцию, используя указатель функции с соответствующими аргументами. Указатель функции может указывать на разные функции условно. (Это можно сделать где-нибудь на этапе инициализации). Более того, описанная выше модель очень полезна, если мы не в состоянии изменить код, в котором она вызывается (предположим, что это API библиотеки, который мы не можем изменить). API использует указатель функции для вызова соответствующей пользовательской функции.
источник
Я постараюсь дать здесь несколько исчерпывающий список:
Обратные вызовы : настройте некоторые (библиотечные) функции с помощью кода, предоставленного пользователем. Ярким примером является
qsort()
, но он также полезен для обработки событий (например, кнопки, вызывающей обратный вызов при нажатии) или необходимости для запуска потока (pthread_create()
).Полиморфизм : vtable в классе C ++ - это не что иное, как таблица указателей на функции. И программа на C также может предоставить vtable для некоторых своих объектов:
Конструктор
Derived
затем установит своюvtable
переменную-член в глобальный объект с реализациями производного классаdestruct
иfrobnicate
, а код, необходимый для разрушения astruct Base*
, просто вызоветbase->vtable->destruct(base)
, который вызовет правильную версию деструктора, независимо от того, какой производный классbase
фактически указывает на .Без указателей на функции полиморфизм нужно было бы закодировать с помощью целой армии конструкций переключателей, таких как
Это довольно быстро становится довольно громоздким.
Динамически загружаемый код : когда программа загружает модуль в память и пытается вызвать его код, она должна пройти через указатель функции.
Все виды использования указателей на функции, которые я видел, попадают в один из этих трех широких классов.
источник