如何在函数中传递函数?

时间:2010-06-10 17:51:40

标签: c++ pointers

这是一个奇怪的头衔。如果有人可以澄清我究竟在问什么,我会非常感激,因为我不太确定自己。

我正在观看有关编程范例的斯坦福视频(那位老师很棒),当他开始这样做的时候,我正在观看视频:

void *lSearch( void* key, void* base, int elemSize, int n, int (*cmpFn)(void*, void*))

当然,我心想,“我,我不知道你可以宣布一个功能并在以后定义它!”。所以我创建了自己的C ++测试版。

int foo(int (*bar)(void*, void*));
int bar(void* a, void* b);

int main(int argc, char** argv)
{
    int *func = 0;
    foo(bar);

    cin.get();
    return 0;
}

int foo(int (*bar)(void*, void*))
{
    int c(10), d(15);
    int *a = &c;
    int *b = &d;
    bar(a, b);
    return 0;
}

int bar(void* a, void* b)
{
    cout << "Why hello there." << endl;
    return 0;
}

关于代码的问题是:如果我将函数int *bar声明为foo的参数,而不是int (*bar),则失败。为什么!?

此外,视频让我感到困惑的是他的lSearch定义

void* lSearch( /*params*/ , int (*cmpFn)(void*, void*))在定义中调用cmpFn,但在调用lSearch函数时

lSearch( /*params*/, intCmp );

也调用定义的函数int intCmp(void* elem1, void* elem2);,但我不知道它是如何工作的。为什么在lSearch中,是一个名为cmpFn的函数,但定义为intCmp,类型为int,而不是int*,仍然有效?为什么lSearch中的函数不必定义参数?

4 个答案:

答案 0 :(得分:10)

int (*cmpFn)(void*, void*)函数指针 - 指向稍后可以调用的函数的指针。当你调用iSearch时,你传递一个函数,它需要两个void*并返回一个int,并将它绑定到参数cmpFn。然后iSearch可以执行int x = cmpFn(voidPtr1, voidPtr2);之类的操作来调用该函数,将voidPtr1voidPtr2作为参数传递,并将返回值存储在x

您可以通过声明一个函数指针并在同一函数中使用它来尝试一个简单的例子:

int test1(int x) {return x;}
int test2(int x) {return x+1;}

int main(int argc, char** argv) {
    int (*fn)(int); // Function pointer named 'fn' that can hold a function that takes one int argument and returns an int
    int rtn;

    fn = test1; // Assign the 'test1' function to 'fn'
    rtn = fn(4); // Call 'fn' ('test1') with the argument 4; it returns 4 and stores it in 'rtn'

    fn = test2; // Assign the 'test2' function to 'fn'
    rtn = fn(4); // Call 'fn' ('test2') with the argument 4; it returns 5 and stores it in 'rtn'
}

如果你声明int *bar它会失败,因为它不是一个函数指针,它只是一个指向整数的指针。函数指针的语法是rtn_type (*name)(param1_type, param2_type, ...)

答案 1 :(得分:4)

  

关于代码的问题是:如果我将函数int * bar声明为foo的参数,而不是int(* bar),则失败。为什么!?

因为您将函数指针声明为指向返回int*的函数的指针。请注意,在参数列表中,函数和函数指针声明之间没有区别,数组和指针声明之间没有区别:

void f(void a());
void f(void(*a)());

void g(int a[]);
void g(int *a);

这些是等价的 - 前两个参数具有函数指针类型,后两个参数具有指针类型。

编写星号和括号是因为它与参数列表之外的含义一致,当然函数指针和函数是不同的东西。

  

为什么在lSearch中,是一个名为cmpFn的函数,但定义为intCmp,它的类型为int,而不是int *并且仍然有效?

星号表示它是指向函数的指针。星星没有附加到返回类型(这就是为什么paren首先在那里 - 绑定到函数而不是返回类型)。

  

为什么lSearch中的函数不必定义参数?

函数指针的参数类型都是重要的。您可以给它们命名,但名称会被忽略。

答案 2 :(得分:2)

有大量的tutorials致力于函数指针。

你的第一个问题的答案是operator*的关联性首先与类型结合。

在第二个示例中,lSearch采用了void*int的函数。这正是intCmp的宣告方式。

无论如何:函数指针在C ++中并不重要。它们应该包含在Functors(已定义operator()的结构)中,您应该使用模板而不是void*

答案 3 :(得分:1)

语法:

int (*cmpFn)(void*, void*)

表示“指向带有两个void *参数并返回int的函数的指针”。括号的放置只是语法的一部分。我怀疑在你有一个函数返回int*int的情况下,有必要帮助消除歧义:

int* (*cmpFn)(void*, void*)

VS

// Ambiguous - could be a pointer to a pointer to a function that returns int, or a pointer
// to a function that returns int*
int* *cmpFn(void*,void*) 

对于调用约定,将cmpFn视为包含函数的变量。名称cmpFn是函数内部变量的名称,但函数名称本身可能不同,就像常规变量一样:

void foo(int x) {
   // Variable is called "x" inside the function
}

void main() {
   int blah = 1;
   foo(blah);  // But it's called "blah" here
}

并且有一个功能:

void myfunction(void *ptr) {
   // Does something.
}

void call_a_function( void (*func)(void*) ) {
   void* someptr;
   func(someptr); // Function is called "func" here.
}

void main() {
  call_a_function(myfunction); // But it's called "myfunction" here.
}