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++语言中,回调函数是通过函数指针来调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。 显然,回调函数并不是由该函数的实现方直接来进行调用的,而是在特定的事件或者条件发生时由另外一方进行调用的,用于对该事件或条件进行响应.

 我们可以这样来理解:  我们把一段可执行的代码,把整个这段代码像参数那样传给其他代码,而这段可执行的代码在某个时刻会被执行,这段代码就是回调函数,这个就叫做回调。

如果代码被立即执行 - 同步回调  代码过后才执行 - 异步回调

 

posted on 2024-01-25 16:59  新西兰程序员  阅读(28)  评论(0编辑  收藏  举报