Один из моих учителей использует это объявление типа:
typedef void (*SortFunction)(int a[], int n);
создать тип, который может содержать указатель на функцию
и это можно использовать для вызова этой функции позже в программе.
Я также знаю, что для передачи функции в качестве параметра вы должны
оберните имя функции в круглые скобки и оберните
параметры в скобках после имени функции, а также так
function someFunction( (anotherfunction)(type arg1, type arg2,...)){
...
}
Я хочу знать, почему вы должны заключать в скобки функцию, подобную этой? это встроенная функция большинства компиляторов с ++ или это просто хитрость, которую мы, программисты, используем
для того, чтобы включить функции в качестве аргументов в нашем коде? Кроме того, почему необходимо ссылаться на «SortFunction» в операторе typedef, почему переменная, которую вы используете для использования SortFunction, просто хранит функцию вместо того, чтобы указывать на нее?
В аргументах функции нет ничего особенного. Всякий раз, когда вы объявляете указатель на функцию (как локальную переменную, глобальную переменную, переменную-член класса, параметр функции, typedef и т. Д.), Он всегда объявляется так:
return_type (*var_name)(T1 param1, T2 param2, /* etc. */ );
// ^
// |
// This * is very important!
куда var_name
Имя переменной указателя функции. Причина, по которой скобки нужны *var_name
происходит из-за приоритета оператора: без скобок *
(указывает, что что-то является указателем) будет соответствовать типу возвращаемого значения функции, и вместо этого вы получите что-то вроде возвращаемого типа int*
(указатель на int
) вместо простого int
,
Вы не можете передать функцию в качестве аргумента, потому что функции не являются первоклассными объектами в C и C ++. Единственный способ передать функцию — это передать указатель на функцию.
Это вопрос синтаксиса. Ты первый typedef
определяет тип, который является функцией, получающей вектор int
и int
и ничего не возвращая (void
).
Переменная типа SortFunction
будет концептуально как любая другая переменная, хотя она указывает на некоторую функцию. Преимущество состоит в том, что вы можете изменить функцию, на которую она указывает, и / или вызвать функцию динамически.
Я хочу знать, почему вы должны заключать в скобки функцию, подобную этой?
Потому что должен был быть какой-то способ идентифицировать указатель на функцию компилятора (точнее, парсера), и этот путь казался таким же хорошим, как и любой другой. В земле C ++ 11 вы можете использовать это вместо: std::function<void(std::array<int>&)>
вместо.
это встроенная функция большинства компиляторов c ++ или это просто уловка, которую мы, программисты, используем для включения функций в качестве аргументов в нашем коде?
Указатели на функции нуждаются в некоторой дополнительной магии, и без поддержки компилятора их было бы очень и очень неудобно использовать. Я также достаточно уверен, что именно в природе программирования почти все хитрости программиста в конечном счете являются функциями компилятора!
Кроме того, почему необходимо ссылаться на «SortFunction» в операторе typedef, почему переменная, которую вы используете для использования SortFunction, просто хранит функцию вместо того, чтобы указывать на нее?
Хм. Не совсем уверен, что вы имеете в виду здесь. Ты имеешь ввиду «почему это должно быть typedef
вообще … почему я не могу просто написать прототип целого указателя функции в аргументах своей функции«? Вы можете:
void foo(void(*funcptr)()) {}
Если бы вы имели в видупочему указатели на функции должны указывать на функцию, а не на встроенный код«Тогда для этого вам нужны C ++ 11 и лямбды:
#include <iostream>
#include <functional>
void foo(std::function<void(void)> bar) { bar(); }
int main(int argc, char* argv[])
{
foo([]() { std::cout << "hi!" << std::endl; });
}
(опять же, специальный синтаксис, необходимый для лямбд, [](){}
просто чтобы разобрать парсер что происходит)
«Я также знаю, что для передачи функции в качестве параметра необходимо заключить имя функции в круглые скобки …» Вы «знаете» неправильно.
Чтобы передать указатель на функцию в качестве параметра, вам не нужно заключать имя в скобки. Например, это будет отлично работать
void foo(int i) {
}
void bar(void f(int)) {
f(5);
}
int main() {
bar();
}
В приведенном выше примере функции bar
получает указатель на функцию foo
в качестве параметра и вызывает foo
через этот указатель, передавая 5
в качестве аргумента. Как видите, имя функции f
в объявлении параметра есть не в скобках.
В этом случае, еще раз, тип параметра f
на самом деле указатель для функции, даже если она явно не объявлена как указатель. Когда тип функции используется в объявлениях параметров функции, он автоматически неявно «заменяется» типом указателя на функцию компилятором.
Если вы хотите явно использовать тип указателя на функцию, вы должны объявить bar
как
void bar(void (*f)(int)) {
f(5);
}
В этом случае скобки в (*f)
необходимо гарантировать, что *
будет связан с f
и не void
, Без скобок void *f(int)
объявление будет означать «возвращение функции void *
«вместо желаемого» указатель на функцию, возвращающую void
».