跳转到内容

C++ 编程/运算符/指针/函数指针

来自维基教科书,开放的书籍,开放的世界

函数指针

[编辑 | 编辑源代码]

我们已经了解过的指针都是数据指针,函数指针(更常见的是函数指针)非常类似,并且与其他指针具有相同的特性,但它们不是指向变量,而是指向函数。创建了一个额外的间接层,作为在 C++ 中使用函数式编程范式的途径,因为它便于调用从同一代码段在运行时确定的函数。它们允许将函数作为参数或返回值传递给另一个函数。

使用函数指针与任何其他函数调用具有完全相同的开销,再加上额外的指针间接,并且由于要调用的函数仅在运行时确定,编译器通常不会像在其他地方那样内联函数调用。由于这种特性,使用函数指针可能会比使用常规函数调用慢得多,应该避免使用它来提高性能。

注意
函数指针主要用于 C,C++ 还允许使用其他结构来启用函数式编程,这些结构称为函数对象(类类型函数对象和模板类型函数对象),与函数指针相比,它们具有一些优势。

要天真地声明一个指向函数的指针,指针的名称必须用括号括起来,否则将声明一个返回指针的函数。你还必须声明函数的返回值类型及其参数。这些必须完全匹配!

考虑

int (*ptof)(int arg);

要引用的函数必须具有与指向函数的指针相同的返回值类型和相同的参数类型。函数的地址可以通过简单地使用其名称来分配,可以选择在前面加上地址运算符 &。可以通过使用 ptof(<value>)(*ptof)(<value>) 来调用函数。

所以

int (*ptof)(int arg);
int func(int arg){
    //function body
}
ptof = &func; // get a pointer to func
ptof = func;  // same effect as ptof = &func
(*ptof)(5);   // calls func
ptof(5);      // same thing.

返回一个float的函数不能由返回一个double的指针指向。如果两个名称相同(例如intsigned,或者typedef名称),则允许转换。否则,它们必须完全相同。你通过将*与变量名称分组来定义指针,就像你对任何其他指针一样。问题是它可能会被解释为返回类型而不是其他类型。

使用 typedef 为函数指针类型定义类型通常更清晰;这还提供了一个地方为函数指针类型指定一个有意义的名称

typedef int (*int_to_int_function)(int);
int_to_int_function ptof;
int *func (int);   // WRONG: Declares a function taking an int returning pointer-to-int.
int (*func) (int); // RIGHT: Defines a pointer to a function taking an int returning int.

为了减少混淆,通常typedef函数类型或指针类型

typedef int ifunc (int);    // now "ifunc" means "function taking an int returning int"
typedef int (*pfunc) (int); // now "pfunc" means "pointer to function taking an int returning int"

如果你typedef函数类型,你可以声明,但不能定义具有该类型的函数。如果你typedef指针类型,你既不能声明也不能定义具有该类型的函数。使用哪种方式是风格问题(尽管指针更流行)。

要将指针分配给函数,你只需将它分配给函数名称。这个&运算符是可选的(它并不模棱两可)。如果存在,编译器将自动选择适合指针的函数的重载版本

int f (int, int);
int f (int, double);
int g (int, int = 4);
double h (int);
int i (int);

int (*p) (int) = &g; // ERROR: The default parameter needs to be included in the pointer type.
p = &h;              // ERROR: The return type needs to match exactly.
p = &i;              // Correct.
p = i;               // Also correct.

int (*p2) (int, double);
p2 = f;              // Correct: The compiler automatically picks "int f (int, double)".

使用指向函数的指针更加简单 - 你只需像调用函数一样调用它。你允许使用*运算符对其进行解引用,但你不需要

#include <iostream>

int f (int i) { return 2 * i; }

int main ()
 {
  int (*g) (int) = f;
  std::cout<<"g(4) is "<<g(4)<<std::endl;    // Will output "g(4) is 8"
  std::cout<<"(*g)(5) is "<<g(5)<<std::endl; // Will output "g(5) is 10"
  return 0;
 }
华夏公益教科书