一. 函数指针
函数指针:指向存放函数空间首地址的指针变量,也就是说,这个指针变量指向一个函数空间的首地址,一般情况下,函数名字就是函数空间的首地址,用一个指针指向这个地址,有点啰嗦。
函数返回值类型 (*指针变量名字)(函数参数列表)
void (*add)(int a,int b,int c ................)
通常情况下,在程序中,会这样定义:
typedef 函数返回值类型 (*指针变量名字)(函数参数列表)
//例如:
//typedef的功能是定义新的类型
//函数指针:
typedef int (*ptrFunc)(int,int);
//意思是:定义了一种 ptrFunc 的类型,并定义这种类型为指向某种函数的指针,
//这种函数以两个int为参数,并返回int类型。
//后面就可以像使用int、char、double..........等变量名字一样使用ptrFunc了。
二. 回调函数和注册函数
简单来说,注册函数就是父函数 回调函数就是子函数 父函数可以指定某个子函数去执行。看代码如下:
#include<stdio.h>
//函数指针
typedef int (*ptrFunc)(int,int);
//4个回调函数
int add(int a,int b)
{
printf("回调函数使用的是add()\n");
return a+b;
}
int sub(int a,int b)
{
printf("回调函数使用的是sub()\n");
return a - b;
}
int mul(int a,int b)
{
printf("回调函数使用的是mul()\n");
return a*b;
}
int div(int a,int b)
{
printf("回调函数使用的是div()\n");
return a/b;
}
//这里写了4个回调函数,它们的签名跟之前定义的函数指针一致,但是完成的是不同的功能。
//下面写一个注册函数,函数的参数分别是 ptrFunc 类型的函数指针,以及两个int型的参数。
//通过这个函数指针,我们就可以将同一函数签名的4个回调函数交给注册函数使用,
//而后边两个int型的参数,刚好给回调函数使用。注册函数和主函数如下:
//注册函数
int Register(ptrFunc callbackFunc,int a,int b)
{
int result = callbackFunc(a,b);
printf("result = %d\n",result);
}
//主函数
int main()
{
int a = 20;
int b = 10;
Register(add,a,b);
Register(sub,a,b);
Register(mul,a,b);
Register(div,a,b);
return 0;
}
函数的执行结果 :
三. C语言通过回调函数实现多态
为了实现多态,我们可以把 register 的参数封装进结构体。修改如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef int (*ptrFunc)(int,int);
//函数指针
typedef int (*ptrFunc)(int,int);
//4个回调函数
int add(int a,int b)
{
printf("回调函数使用的是add()\n");
return a+b;
}
int sub(int a,int b)
{
printf("回调函数使用的是sub()\n");
return a - b;
}
int mul(int a,int b)
{
printf("回调函数使用的是mul()\n");
return a*b;
}
int vip(int a,int b)
{
printf("回调函数使用的是vip()\n");
return a/b;
}
//结构体
typedef struct data
{
int a;
int b;
ptrFunc callback; //函数管理器
}data_t;
//首先在函数指针下创建一个结构体,结构体中的数据包括两个 int 和一个函数指针。
//这个函数指针,称其为函数管理器,注册函数现在传入的不再是3个参数,
//而是打包了这三个参数的结构体:
//注册函数
int Register(data_t *test)
{
int result = test->callback(test->a,test->b);
printf("result = %d\n",result);
}
//在主函数中调用的时候
int main()
{
data_t *my_data = (data_t *)malloc(sizeof(data_t));
my_data->a = 20;
my_data->b = 10;
my_data->callback = add; //改变函数管理器
Register(my_data);
my_data->callback = sub; //改变函数管理器
Register(my_data);
my_data->callback = mul; //改变函数管理器
Register(my_data);
my_data->callback = vip; //改变函数管理器
Register(my_data);
free(my_data);
return 0;
}
可以发现,虽然 Register 函数参数没变过,都是my_data,但是通过改变函数管理器中的值,就可以改变Register(my_data)的输出。这就实现了C语言的多态,面向对象的多态的实现原理是一样的。