函数指针指向的是函数而非对象。和其它指针一样,函数指针指向某种特定类型。函数的类型由它的返回值类型和形参类型共同决定,与函数名无关。例如:
int f(int a, double b);
// 它的指针
int (*pf)(int a, double b)
括号是必须得有的,如果没有括号,如
int *pf(int a, double b);
则该声明为一个返回值为int型指针的函数
1. 使用函数指针
当我们把函数名作为一个值使用时,该函数会自动地转换成指针。例如,按照如下形式,我们可以将f的地址赋给pf
pf = f; // pf指向名字为f的函数
pf = &f; // 等价
使用指向函数的指针调用函数,不需要解引用指针
int f1 = pf(1, 3.14);
int f2 = (*pf)(1, 3.14);
int f3 = f(1, 3.14);
// 这三个方法是等价调用的
2.重载函数指针
当我们使用重载函数时,上下文必须清晰地界定到底应该选用哪个函数。如果定义了指向重载函数的指针,那么编辑器通过指针类型决定选用哪个函数,指针类型必须与重载函数中的某一个精确匹配(即形参类型完全一样)。
void f(int*);
void f(unsigned int);
void (*pf)(unsigned int) = f; // pf指向f(unsigned int)
void (*pf1)(int) = f; // 错误,没有任何一个f与该形参列表不匹配
double (*pf2)(int*); // 错误,返回值类型不同
3.函数指针形参
和数组类似,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。此时,形参看起来是函数类型,实际上却是当成指针使用。
void function1(int a, int pf(int, double)); // 第二个形参是函数类型,他会自动的转成函数指针
void function2(int a, int (*pf)(int, double)); // 等价声明
我们可以把已经声明的函数作为实参直接使用,它会自动的转为指针
function1(1, f(2, 3.14));
这是不是和lambda表达式很像呢?
4.返回指向函数的指针
又和数组类似,虽然不能返回一个函数,但是能返回指向函数类型的指针。然而,我们必须把返回类型写成指针形式,编译器不会自动的将函数返回类型当成对应的指针类型处理。与往常一样,要想声明一个返回函数指针的函数,最简单的办法是使用类型别名。
using F = int(int, double); // F是参数为(int, double)的函数类型
using pF = (int*)(int, double); // pf是参数为(int, double)的函数指针类型
// 函数调用
pF f(int);
F* f(int);
F f(int); // 错误,返回值不能有函数类型。
当然,我们也能用下面的形式直接声明
int (*f(int))(int, double);
按照由内向外的顺序阅读它:我们看到f有形参列表,那么f为函数;f前有*,所以f返回一个指针,则化为int(*)(int, double)的形式,这样就是函数指针了。(指针类型也包含有形参,所以指针指向函数,返回int)。
还可以用尾置返回类型的方式声明一个返回函数指针的函数
auto f(int, double) -> int(*)(int, double);