函数指针 (C++)

3

我正在学习C++教程。我不理解指向函数的指针的这个例子。下面是例子:

// pointer to functions
#include <iostream>
using namespace std;

int addition (int a, int b)
{ return (a+b); }

int subtraction (int a, int b)
{ return (a-b); }

int operation (int x, int y, int (*functocall)(int,int))
{
  int g;
  g = (*functocall)(x,y);
  return (g);
}

int main ()
{
  int m,n;
  int (*minus)(int,int) = subtraction;

  m = operation (7, 5, addition);
  n = operation (20, m, minus);
  cout <<n;
  return 0;
}

这两行代码 "m = operation (7, 5, addition);" 和 "n = operation (20, m, minus);" 被处理方式相同,但是减法被声明为一个函数指针,而加法没有。那么它们是如何以相同的方式工作的呢?

6个回答

5

在C/C++中,将函数名用作函数调用中的参数或赋值运算符右侧的参数会导致将原始函数转换为函数指针。

例如,如果您有一个函数:

void my_function(int a, int b);

如果在赋值操作符的右侧像这样使用标识符my_function:
void (*my_function_ptr)(int, int) = my_function;

那么my_function隐式地从函数对象转换为类型为void (*)(int, int)的函数指针,初始化标识符my_function_ptr,使其指向my_function。当将my_function传递给另一个函数时,也会出现同样的情况:

void another_function(int, void (*)(int, int));
another_function(5, my_function);

在调用another_function()函数时,标识符my_function被再次转换为指向原始函数的指针。
最后,请记住,只有在将标识符名称简单地传递给函数参数或将其放在赋值运算符的右侧时才会发生此情况。添加一个使用()符号和可选参数列表的函数调用(即my_function(5, 6))将评估该函数,而不是导致函数指针的转换。

一个很好的回答,但是你所说的“C类型”函数并不清楚。从类型上来看,函数和指向函数的指针是不同的,这种差异在某些情况下是可见的。 - Alexey Kukanov

4
addition的类型是int (&)(int,int),它可以衰减为指针类型int (*)(int,int),这与operation函数的第三个参数的类型相同。因此,您可以将addition作为operation函数的第三个参数传递。

subtraction的类型也与addition相同。在您的代码中,subtraction的地址首先作为兼容类型的局部变量存储,然后将该变量作为参数传递给operation函数。

对于addition,其地址不会被存储为局部变量,而是直接作为参数传递给operation。它直接使用函数地址初始化函数的第三个参数,而没有使用任何局部变量。

在两种情况下都发生了从int (&)(int,int)int (*)(int,int)的转换。只是在substration的情况下,转换发生在初始化局部变量时,在addition的情况下,转换发生在初始化函数参数时。

一个类比可能是这样的:

void f(double a, double b) {}

int main()
{
   double x = 100;//first store 100 in a local variable
   f(x, 100);  //pass the local variable as first arg, 
               //and pass 100 as second arg without using any local variable.
}

请注意,100的类型是int,因此它首先转换为double类型,然后存储为局部变量x,该变量随后作为第一个参数传递给函数f。第二个参数100直接传递给函数,因此即使现在它也会首先转换为double,然后初始化函数的第二个参数b
再次强调,在这两种情况下都发生了从intdouble的转换。只是第一个参数的转换发生在初始化局部变量x时,而第二个参数的转换发生在初始化函数的第二个参数时。

实际上,int (&)(int, int) 不会衰减为函数指针 - 另一方面,int(int,int) 会。但除此之外,非常精确的答案,所以+1. :) - Vitus
@Vitus:据我所知,int(int,int)int(*)(int,int)是一样的,没有区别。另外,int(&)(int,int)可以转化为函数指针:http://www.ideone.com/YcLVj - Nawaz
我不相信它会“衰减”——更可能是发生了其他转换。有三种类型的衰减——lvalue到rvalueT数组到T指针函数F到函数F指针(§4.1到§4.3,以及§20.9.7.6,“decay”结构体——至少在最新的草案中)。但另一方面,lvalue引用的行为就像lvalue... - Vitus

2

C语言中的函数名称会被解析成其地址。因此,以下代码是有效的:

int (*minus)(int,int) = subtraction;

1

两种解决方案都可行: "operation" 的第三个参数必须是函数指针。

请注意,符号 & 是可选的:

m = operation (7, 5, &addition);

同样适用。


0
通过将"addition"传递给operation(),你实际上是将它分配给了"functocall"。这与将"subtraction"分配给"minus"完全相同。它们之所以能够正常工作,是因为它们是一样的。
真正的问题是,为什么不需要使用&符号来获取函数的地址呢?
附注:除了滥用iostream、namespace和cout之外,这实际上是一个C教程,对吗?

0

C++提供了隐式函数指针转换(请参见C++ 2003标准中的4.3节)。在您的示例中,它既用于将subtraction赋值给minus,又用于将addition转换为operation接受的参数类型。因此,在这两种情况下,调用方式都是相同的,只是在一种情况下,您明确地创建了一个指向函数的指针类型的中间变量。在这两种情况下,优化编译器将简单地将相应函数的地址传递到operation中。


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