如何在C++中将函数指针传递给函数?

4

这里有三个函数,分别是:

float Plus    (float a, float b) { return a+b; }
float Minus   (float a, float b) { return a-b; }
float Multiply(float a, float b) { return a*b; }

现在有一个函数,需要将一个指向函数的指针作为其中一个参数:

void Function_Pointer_func(float a, float b, float (*pt2Func)(float, float))
{
   float result = pt2Func(a, b);    // call using function pointer

   cout << " Result = ";  // display result
   cout << result << endl;
}

并且要调用上面的函数“Function_Pointer_func”,下面是该函数的写法。
void Replace()
{ 
   Function_Pointer_func(2, 5, /* pointer to function 'Minus' */ Plus);////   (1)
   Function_Pointer_func(2, 5, /* pointer to function 'Minus' */ &Minus);//// (2)

}

为什么上述函数能够正常工作,因为 "Function_Pointer_func" 函数将函数指针作为参数传递。如果我们替换第 line 中的 RHS
 float result = pt2Func(a, b);    // call using function pointer 

将函数“Function_Pointer_func”中的(*pt2Func)(a, b)替换为(pt2Func)(a, b),同样也可以工作,但对于(&pt2Func)(a, b)会出现VS2008错误:

"error C2064:项不会评估为接受2个参数的函数"

现在,在函数“Function_Pointer_func”的“float (*pt2Func)(float, float)”参数中替换为“float (pt2Func)(float, float)”,然后三个都可以正常工作。

float result = pt2Func(a, b);    // 
float result = (&pt2Func)(a, b); // 
float result = (*pt2Func)(a, b); // 

函数指针是什么?为什么会起作用?我希望我的疑惑源于对函数指针核心理解的不足。虽然我已经进行了一些阅读,但我还没有进行深入的研究,所以请随意推荐相关的阅读材料来澄清我的疑虑。

提前感谢您的帮助。


已经有一个完美的 std::plus<float>,不需要编写自己的。 - MSalters
感谢 @RiaD 指出的问题,导致所有三种类型都能工作可能是 msvc 的一个 bug/feature。这确实消除了疑虑,但我会尝试在其他编译器中进行相同的测试。 - zeal
2个回答

2

这是C++标准。

float Plus(float a, float b);
void Function_Pointer_func(float a, float b, float (*pt2Func)(float, float));

Function_Pointer_func(2, 5, Plus); // (1)
...
float result = pt2Func(a, b); // (2)

(1) 函数指针的转换 (标准2003, 4.3):

An lvalue of function type T can be converted to an rvalue of
type “pointer to T.” The result is a pointer to the function

(2)是函数调用(标准2003,5.2.2):

For an ordinary function call, the postfix expression shall be either
an lvalue that refers to a function (in which case the function-to-pointer
standard conversion (4.3) is suppressed on the postfix expression), or it
shall have pointer to function type.

[更新] 详细说明如下:

void Replace() { 
   Function_Pointer_func(2, 5, Plus);
   Function_Pointer_func(2, 5, &Minus);
}

Minus是一个函数,&Minus是指向该函数的指针,因此没有转换,Function_Pointer_func的第三个参数非常匹配。

Plus是一个函数,因此需要将其转换为指针才能适应Function_Pointer_func。标准(1)说可以自动完成这个过程。

调用情况:

void Function_Pointer_func(float a, float b, float (*pt2Func)(float, float)) {
   float result = pt2Func(a, b); // call by pointer, see (2)
   float result = (*pt2Func)(a, b); // convert pointer to function, so 'normal' call
   float result = (&pt2Func)(a, b); // pointer to function pointer, nope, will not work
}

我不理解你的回答,请花点时间解释或提供一些参考。 - zeal

2

函数会自动衰变为函数指针。

  • 在这种情况下,如果没有指定,function_name实际上是指 &function_name

  • &function_name将函数转换为函数指针。

  • *function_name实际上是指 *(function_name),根据上述操作变成了 *(&function_name)*& "相互抵消",因此最终的 function_name 又衰变回了 &function_name


@jrok,你说“函数自动衰减为函数指针”,这解决了我的一些困惑,但我仍然有疑问。正如你在第三个语句中所说的那样,*function_name最终会变成(&function_name),但&function_name呢?如果函数中的一个参数是(pt2Func)(float, float),那么为什么所有三种类型都可以工作,请就此发表评论。 - zeal
@zeal 我没有说过那个,是一个访客说的 :) 无论如何,当 f 是一个函数名时,&f 给你一个函数指针。当 f 已经是一个函数指针时,&f 给你一个 指向函数指针的指针,这不能在函数调用中使用。 - jrok
@ruslo:他有一点道理:如果您在非调用上下文中使用函数名称(即作为function_name而不是function_name(args)),则通常会引用函数地址。但确实:sizeof(function_name)是非法的,而sizeof(&function_name)是可以的,因此存在明显的差异。 - MSalters
@jrok,抱歉让你感到不适,请允许我再次感谢您澄清疑问。如果您看到这条消息,请回答我的另一个问题,该问题与指针有关。虽然您可能会说这个问题已经有答案了,但是我修改了问题,请再次帮我解除疑惑。 - zeal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接