函数指针 & 返回函数指针的函数
一、函数指针的声明和使用
声明一个函数指针,给它赋值并调用它指向的函数
函数指针就是一个指向函数的指针。
先来简单看一下怎么使用函数指针。我们声明一个函数,和一个指向该函数类型的指针,让指针指向该函数并通过指针调用它。
#include<iostream>
using namespace std;
//定义一个返回值为int、参数表为(char,double)的函数
int func(char c, double d) {
cout << c << " = " << d << endl;
return 0;
}
int main() {
//p_int是一个指向返回值为int、参数表为(char,double)的函数的指针
int (*p_int)(char, double);
//让p_int指向函数func
p_int = &func;
//通过函数指针p_int调用func
(*p_int)('A',3.14);
return 0;
}
输出结果:A = 3.14
可以这样描述p_int:它指向一个返回值为int、参数表为(char,double)的函数。声明函数指针的句子是int (*p_int)(char, double),我们可以这样理解它:
-
p_int前面的*说明它是一个指针 -
(*p_int)的右侧是一个形参表,这说明该指针指向一个函数 -
(*p_int)的左侧是int,这说明该指针指向的返回值是int类型
注意(*p_int)两侧的括号不能省略,否则句子就会变成int *p_int(char,double),这是一个函数,函数名为p_int,返回值是一个int型指针。
当p_int的值为0或nullptr时,说明它不指向任何函数。
等价的表达
(1)在给函数指针赋值时,以下语句作用是相同的:
p_int = &func;
p_int = func;
第一个的句子意义很显然:把函数func的地址赋给p_int;而由于我们把函数名当作一个值使用时,它会自动地转换成指针,则第二个的句子也做了一样的事情。
(2)在使用函数指针调用函数时,以下语句作用是相同的:
(*p_int)('A',3.14);
p_int('A',3.14);
不论是对p_int解引用还是直接使用p_int,都可以成功地调用它指向的函数。
二、函数指针作为形参传递
函数的形参列表中不能定义函数类型的形参,所以要把一个函数作为另一个函数的参数需要使用函数指针类型的形参:
#include<iostream>
using namespace std;
//定义一个返回值为int、参数表为(char,double)的函数
int func(char c, double d) {
cout << c << " = " << d << endl;
return 0;
}
//定义一个函数,形参列表中包含func这一类型的函数
void use_pointer_of_func(char c, double d,int (*p)(char,double)) {
p(c,d);
}
int main() {
//把func作用参数调用
use_pointer_of_func('A', 3.14, &func);
//写作use_pointer_of_func('A', 3.14, func)也是可以的
}
在函数use_pointer_of_func的形参列表中,int (*p)(char,double)就是一个函数指针类型的形参。然而如果(*p)指向的函数形参列表很长,如int (*p)(char,double,double,double,char,char,char.......),这时候可以用decltype和typedef来简化语句:
typedef decltype(func) *F;
//写作typedef int (*F)(*char c, double d)也是等价的
void use_pointer_of_func(char c, double d, F) ......
更改后代码如下:
#include<iostream>
using namespace std;
//定义一个返回值为int、参数表为(char,double)的函数
int func(char c, double d) {
cout << c << " = " << d << endl;
return 0;
}
typedef decltype(func)* F;
//写作typedef int (*F)(*char c, double d)也是等价的
//定义一个函数,形参列表中包含func这一类型的函数
//F是func类型的函数指针的别名
void use_pointer_of_func(char c, double d, F p) {
p(c, d);
}
int main() {
//把func作用参数调用
use_pointer_of_func('A', 3.14, &func);
//写作use_pointer_of_func('A', 3.14, func)也是可以的
}
三、返回值为函数指针类型的函数
以上说了函数本身不能作为形参,同样的,函数也不能作为返回值,但是我们可以返回指向函数的指针。以下是一个名为f的函数,它的参数表是(string),它返回一个函数指针,指向一个参数表为(char,double)返回值为int的函数:
int (*f(string))(char, double);
我们来理解一下这个语句:
-
f有形参列表(string),所以f是一个输入参数为一个字符串的函数 -
f前面有*,说明f返回的是一个指针 - 指针
(*f(int))右侧有形参列表(char, double),说明f返回的指针指向一个函数,(char, double)是该函数的形参表。 - 最左边的
int说明被指向的函数返回值是int类型
上面的写法有点绕,我们可以用using来简化它:
using F = int(char,double);
F *f(string);
该写法与int (*f(string))(char, double)等价,并且含义较容易理解:函数f读入一个string参数返回一个F*类型的值,而F是一个读入参数表(char,double),返回一个int的函数。
你也可以直接把F作为函数指针:
using F = int(*)(char,double);//F是函数指针类型
F f(string);//f的返回类型是函数指针