C++中的函数指针
C++中的函数指针是一个非常灵活的东西,刚开始接触这个概念时,有点难以理解。看了几篇文章介绍后,想在这里做个总结
首先,我们要明白,在C++中,函数是有地址的。在C++中,可以用函数名来表示函数的地址,也可以在函数名之前加上取地址符合“&”来表示函数地址
比如 下面是一个函数
int add(int x, int y) { return x + y; }
add()函数的地址可以用函数名add或者&add表示.
我们都知道,指针是用来存储地址的,通常,一个指针如果指向一个变量a,那么它存储的就是变量a的地址
而我们上面说了,函数也是有地址的,那么我们自然也会想到把指针指向函数,也就是说指针用来储存函数的地址。
但是函数和变量总是有区别的,函数占用的内存会更大,它可能是一个连续的内存块,这时,我们这里所说的函数的地址,指的就是函数的入口地址,也就是说,一个指针,只要存储了某个函数的入口地址,这个指针就是指向这个函数的指针
在C++中,我们知道,指针指向变量时,它可以变更指向,指向不同的变量。 那么同理,指向函数的指针,也可以变更指向,从而指向不同的函数。
我们可以通过函数指针能调用其指向的函数,从而使得函数调用更加灵活
现在我们来仔细看看如何定义函数指针
定义一个函数指针的格式如下
返回值类型 (*函数指针名)(参数列表);
比如,我们要定义一个指向返回值类型为int, 参数列表为(int,int)的函数指针
int (*fPtr) (int, int)
上面这个函数指针,fPtr是函数指针的名称,特别注意,不能写成这样
int *fPt(int,int) => 这样,它等价于 int* fPtr(int,int) =》 看到没,它就是一个函数,函数名是fPtr,返回值是int类型的指针
所以,要表示函数指针,括号一定不能省掉,括号改变了运算符的优先级,没有括号,就成了函数,不是函数指针
为了方便使用,我们一般这样写
typedef 返回值类型 (*函数指针名)(参数列表);
eg:
typedef int (*Fun1) (int,int); //参数为2个整形,返回值为整形的函数指针
2. 用函数指针来调用函数
举个例子如下:
int TestFunc(int x); //声明一个函数 int (*p) (int x); // 定义一个函数指针 p = TestFunc; //将TestFunc函数的首地址赋给函数指针变量p p = &TestFunc; //将TestFunc函数的首地址赋给函数指针变量p
在C++中,对于函数而言,函数名代表的就是函数的首地址,所以我们可以直接用函数名TestFunc来代表函数的首地址,当然也可以用&TestFun
函数指针调用函数举例:
#include <stdio.h>
int Min(int, int); //函数声明
int main(void)
{
int(*p)(int,int); //定义一个函数指针
int x, y ,z;
p = Min; //把函数赋给函数指针变量p,使p指向Min函数
z = (*p)(x,y); //通过函数指针调用Min函数
z = p(x,y); //这句和上面是等价的,也可以这样写.通过函数指针p调用Min函数
return 0;
}
// 定义Min函数 int Min(int a, int b) { int c; if(a > b) { c = b; } esle { c = a; } return c; }
从上面的例子可以看出,z = (*p) (x, y) 和 z = p(x,y) 是等价的,通过函数指针调用函数,这两种写法都可以
3. 函数指针作为某个函数的参数
我们知道,是不能把一个函数作为另一个函数的参数的,但是函数指针却可以,为什么呢? 这样理解,函数指针是一个变量 => 函数指针变量, 既然是一个变量,那自然就可以作为某个函数的参数来进行使用
通常,函数指针作为某个函数的参数,在这个函数内部是作为回调函数来使用的,我们来看一个例子,就会更直观的明白
#include <stdio.h> #include <stdlib.h> typedef void (*TestFun)(int); //定义一个函数指针, 参数是int类型,返回值为void类型 //定义函数 void myFun(int x); void thisFun(int x); void thatFun(int x); void callFun(TestFun fp,int x); //把函数指针TestFun fp作为参数,因为函数指针fp可以看成是一个变量 => 函数指针变量
int main()
{
callFun(myFun,10); // 传入函数指针myFun,作为回调函数
callFun(thisFun,20); //传入函数指针thisFun, 作为回调函数
callFun(thatFun,30); //传入函数指针thatFun,作为回调函数
return 0;
}
//现在我们来看看这个把函数指针作为参数的函数callFun是怎么实现的
void callFun(TestFun fp,int x)
{
fp(x); //通过fp的指针指向传递进来的函数,注意fp所指的函数有一个参数
}
4. 函数指针作为函数的返回类型
这个我没有找到具体的例子,但可以做如下讲解:
上面第3点中提到,函数不能作为一个函数的参数,同样的道理,函数也不能作为另一个函数的返回值。但是函数指针可以,因为它可以看作是一个函数指针变量, 既然是变量,自然就可以作为返回值. 我们来看一个例子:
int (*f(string))(char,double);
我们从内到外来理解一下这个函数:
(1). f有形参列表f(string) => 所以f是一个输入参数为一个字符串的函数
(2). f前面有*, 说明f返回的是一个指针
(3). 指针(*f(int))
右侧有形参列表(char, double)
,说明f
返回的指针指向一个函数,(char, double)
是该函数的形参表。
(4) 最左边的int
说明被指向的函数返回值是int
类型
5. 函数指针数组
我们知道,数组中是可以存放指针的,既然函数指针也是指针,那么我们应该就可以用数组来存放函数指针. 下面我们来看一下如何定义函数指针数组
// 定义 函数指针数组的方法1 void (*func_array[5])(int,int,double);
//定义 函数指针数组的方法2
typedef void (*p_func_array)(int, int ,double);
p_func_array testFun_array[5];
回调函数
C和C++语言中很多时候就会用到回调函数,但是回调函数并不是C或者C++语言特有的,几乎任何语言都有回调函数。在C或者C++中,我们通过使用函数指针来实现回调函数‘
回调函数 =》 在C或者C++语言中,回调函数是通过函数指针来调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。 显然,回调函数并不是由该函数的实现方直接来进行调用的,而是在特定的事件或者条件发生时由另外一方进行调用的,用于对该事件或条件进行响应.
我们可以这样来理解: 我们把一段可执行的代码,把整个这段代码像参数那样传给其他代码,而这段可执行的代码在某个时刻会被执行,这段代码就是回调函数,这个就叫做回调。
如果代码被立即执行 - 同步回调 代码过后才执行 - 异步回调