0

我的一位老师使用这种类型声明:

typedef void (*SortFunction)(int a[], int n);

创建一个类型,该类型可以保存指向函数的指针,并且可以用于稍后在程序中调用该函数。

我也知道,要将函数作为参数传递,您必须将函数名括在括号中,并将函数的参数括在函数名之后的括号中,就像这样

function someFunction( (anotherfunction)(type arg1, type arg2,...)){
  ...
} 

我想知道的是为什么你必须像这样在括号中包装一个函数?这是大多数 c++ 编译器的内置函数,还是我们程序员为了在代码中启用函数作为参数而使用的一种技巧?还有,为什么需要引用typedef语句中的“SortFunction”,为什么你用来利用SortFunction的变量不能只保存函数而不是指向它?

4

4 回答 4

1

函数参数没有什么特别之处。每当您声明一个函数指针(作为局部变量、全局变量、类成员变量、函数参数、typedef 等)时,它总是这样声明:

return_type (*var_name)(T1 param1, T2 param2, /* etc. */ );
//           ^
//           |
// This * is very important!

var_name函数指针变量的名称在哪里。需要括号的原因*var_name是由于运算符优先级:没有括号,*(指示某物是指针)将与函数的返回类型匹配,相反,您会得到类似int*(指向int)的返回类型平原int

您不能将函数作为参数传递,因为函数不是 C 和 C++ 中的一等对象。传递函数的唯一方法是传递一个指向函数的指针。

于 2012-11-12T18:20:52.197 回答
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”。

于 2012-11-12T18:52:14.393 回答
0

这是语法问题。您首先typedef定义了一个类型,它是一个接收int和 a的向量int并且不返回任何内容的函数 ( void)。

类型变量 SortFunction在概念上与任何其他变量一样,尽管它指向某个函数。优点是您可以更改它指向的函数和/或动态调用该函数。

于 2012-11-12T18:21:04.457 回答
0

我想知道的是为什么你必须像这样在括号中包装一个函数?

因为必须有某种方法来识别指向编译器(或者更确切地说,解析器)的函数指针,而且这种方法看起来和任何方法一样好。在 C++11 领域,您可以改用它:std::function<void(std::array<int>&)>代替。

这是大多数 c++ 编译器的内置函数,还是我们程序员为了在代码中启用函数作为参数而使用的一种技巧?

函数指针需要一点额外的魔法,如果没有编译器的支持,它们使用起来会非常非常不方便。我也相当肯定,几乎所有程序员的技巧最终都是编译器的功能,这在编程的本质上是有道理的!

还有,为什么需要引用typedef语句中的“SortFunction”,为什么你用来利用SortFunction的变量不能只保存函数而不是指向它?

唔。不完全确定你在这里的意思。你的意思是“为什么这需要一个typedef...为什么我不能在我的函数参数中写出整个函数指针原型”?因为你可以:

void foo(void(*funcptr)()) {}

如果您的意思是“为什么函数指针必须指向函数而不是内联代码”,那么为此您需要 C++11 和 lambda:

#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 需要特殊语法[](){},只是告诉解析器发生了什么)

于 2012-11-12T18:41:09.643 回答