我的一位老师使用此类型声明:
typedef void (*SortFunction)(int a[], int n);
创建一个可以保存指向函数的指针的类型 这可以用来稍后在程序中调用该函数。
我也知道要将函数作为参数传递 将函数名称括在括号中并包装函数 函数名后的括号中的参数也是如此
function someFunction( (anotherfunction)(type arg1, type arg2,...)){
...
}
我想知道为什么你必须在这样的括号中包装一个函数?这是大多数c ++编译器的内置函数,还是我们程序员使用的技巧 为了在我们的代码中启用函数作为参数?还有,为什么“SortFunction” 在typedef语句中需要引用,为什么你用来使用SortFunction的变量只能保存函数而不是指向它?
答案 0 :(得分:1)
函数参数没有什么特别之处。每当你声明一个函数指针(作为局部变量,全局变量,类成员变量,函数参数,typedef等)时,它总是被声明为:
return_type (*var_name)(T1 param1, T2 param2, /* etc. */ );
// ^
// |
// This * is very important!
其中var_name
是函数指针变量的名称。围绕*var_name
需要括号的原因是由于运算符优先级:没有括号,*
(表示某些东西是指针)与函数的返回类型匹配,而是你得到的东西像返回类型int*
(指向int
)而不是普通int
。
您不能将函数作为参数传递,因为函数不是C和C ++中的第一类对象。传递函数的唯一方法是传递一个指向函数的指针。
答案 1 :(得分:1)
“我也知道要将函数作为参数传递,你必须将函数名称括在括号中......”你“错误地”知道了。
为了将函数指针作为参数传递,您不必将名称包装在括号中。例如,这将完美无缺
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
函数的指针”。
答案 2 :(得分:0)
这是语法问题。您的第一个typedef
定义了一个类型,该类型是一个接收int
和int
向量并且不返回任何内容(void
)的函数。
类型SortFunction
的变量在概念上将与任何其他变量一样,尽管它指向某个函数。优点是您可以更改它指向的功能和/或动态调用该功能。
答案 3 :(得分:0)
我想知道为什么你必须在这样的括号中包装一个函数?
因为必须有某种方法来识别指向编译器(或者更确切地说是解析器)的函数指针,并且这种方式看起来和任何方式一样好。在C ++ 11中,您可以使用它代替:std::function<void(std::array<int>&)>
。
这是大多数c ++编译器的内置函数,还是我们程序员使用的一个技巧,以便在我们的代码中启用函数作为参数?
函数指针需要一些额外的魔力,如果没有编译器支持,它们将非常非常不方便使用。我也有理由相信,编程本质上几乎所有的程序员技巧都是编译器的最终功能!
另外,为什么需要引用typedef语句中的“SortFunction”,为什么用于利用SortFunction的变量只能保存函数而不是指向它?
嗯。不完全确定你的意思。你的意思是“为什么这需要一个typedef
...为什么我不能在函数参数中写出整个函数指针原型”?你可以:
void foo(void(*funcptr)()) {}
如果你的意思是“为什么函数指针必须指向一个函数而不是代码内联”那么你需要C ++ 11和lambdas:
#include <iostream>
#include <functional>
void foo(std::function<void(void)> bar) { bar(); }
int main(int argc, char* argv[])
{
foo([]() { std::cout << "hi!" << std::endl; });
}
(同样,lambdas需要特殊的语法,[](){}
,只是为了告诉解析器发生了什么)