C/C++面向对象(OOP)编程-回调函数详解(回调函数、异步编程、函数指针、)
本文主要介绍回调函数的使用,包括函数指针、异步回调编程、主要通过详细的例子来指导在异步编程和事件编程中如何使用回调函数来实现。
🎬个人简介:一个全栈工程师的升级之路!
📋个人专栏:C/C++精进之路
🎀CSDN主页?发狂的小花
🌄人生秘诀:学习的本质就是极致重复!
目录
1 回调函数
????????回调函数是一种特殊的函数,它作为参数传递给另一个函数,并在被调用函数执行完毕后被调用。这种机制常用于事件处理、异步编程和处理各种操作系统和框架的API。
具体来说,一个函数可以将其它的函数(也就是回调函数)作为参数传入,当特定的事件触发或者任务完成时,这个被传入的函数就自动执行。这样的设计使得代码更加模块化,增强了代码的可读性和可重用性。
? ? ? ? 回调函数是一种设计理念,与编程语言无关,C语言中可以通过函数指针实现回调函数。
? ? ? ? 回调函数主要用于异步编程和事件处理中。
????????回调函数提供了一种强大的工具,允许我们将复杂的问题分解为更小的部分进行解决,同时也增加了代码的灵活性和扩展性。
2 C语言回调函数
? ? ? ? C语言的回调函数是使用函数指针实现的,函数作为参数传给另一个函数,传参的函数被称为回调函数。
2.1 函数指针
2.1.1 函数指针变量
? ? ? ? 指向函数的指针变量称为函数指针。本质上是一个指针。
? ? ? ? 定义方式:
????????返回类型 (*指针变量名)(参数列表);
????????其中,返回类型表示函数返回值的类型,参数列表表示函数接受的参数类型和个数。指针变量名就是函数指针的名称,它可以像普通变量一样被赋值和使用。
? ? ? ? 使用实例:
??例如,定义一个指向返回值为int类型、接受两个int类型参数的函数的指针:
int (*pFunc)(int, int);
C++中可以使用new运算符动态分配内存来存储函数指针:
int (*pFunc)(int, int) = new int(*func)(int a, int b);
其中,func是一个已定义的函数,pFunc是指向该函数的指针。使用delete运算符释放内存:
delete pFunc;
2.1.2 定义函数类型
? ? ? ?定义方式:
? ? ? ? typedef?返回类型 新的函数名(参数列表);
? ? ? ? 使用实例:
定义一个返回类型是int,参数为两个int数据,的函数类型
typedef int INT_func(int,int);
? ? ? ? 调用方式:
int sub(int a, int b)
{
return (a-b);
}
// add 为指针类型,函数的地址,因此需要声明变量为指针类型
INT_func *add_p = add;
int ret = add_p(12,13);
一个例子:
#include <stdio.h>
typedef int INT_func(int,int);
int add(int a,int b)
{
return (a+b);
}
int sub(int a, int b)
{
return (a-b);
}
int multi(int a,int b)
{
return (a*b);
}
int main()
{
INT_func *add_p = add;
int ret = add_p(12,13);
printf("12+13 = %d \n",ret);
INT_func *sub_p = sub;
int ret1 = sub_p(12,13);
printf("12-13 = %d \n",ret1);
INT_func *mutti_p = multi;
int ret2 = mutti_p(12,23);
printf("12*13 = %d \n",ret2);
return 0;
}
? ? ? ? 运行结果:
2.1.3 定义函数指针类型
?????????定义方式:
? ? ? ? typedef?返回类型 (*新的函数名)(参数列表);
? ? ? ? 使用实例:
定义一个返回类型是int,参数为两个int数据,的函数类型
typedef int (*INT_func)(int,int);
? ? ? ? 调用方式:
int sub(int a, int b)
{
return (a-b);
}
// add 为指针类型,函数的地址,因此需要声明变量为指针类型
INT_func add_p = add;
int ret = add_p(12,13);
一个例子:
#include <stdio.h>
typedef int (*INT_func)(int,int);
int add(int a,int b)
{
return (a+b);
}
int sub(int a, int b)
{
return (a-b);
}
int multi(int a,int b)
{
return (a*b);
}
int main()
{
INT_func add_p = add;
int ret = add_p(12,13);
printf("12+13 = %d \n",ret);
INT_func sub_p = sub;
int ret1 = sub_p(12,13);
printf("12-13 = %d \n",ret1);
INT_func mutti_p = multi;
int ret2 = mutti_p(12,23);
printf("12*13 = %d \n",ret2);
return 0;
}
? ? ? ? 运行结果:
2.2 C语言回调函数实例
????????在C语言中,回调函数是一种常见的编程模式,它允许一个函数作为参数传递给另一个函数。这种特性使得我们可以将一些特定的任务委托给其他函数来完成。
#include <stdio.h>
// 定义一个函数指针类型
typedef void (*Callback)(int);
// 定义一个函数,接受一个回调函数作为参数
void do_something(Callback callback) {
// 在这里做一些操作...
printf("Doing something...\n");
// 然后调用回调函数
callback(42);
}
// 定义一个回调函数
void my_callback(int data) {
printf("Callback called with data: %d\n", data);
}
int main() {
// 将回调函数传递给do_something函数
do_something(my_callback);
return 0;
}
????????在这个例子中,do_something
函数接受一个Callback
类型的参数,这是一个指向函数的指针。然后,do_something
函数调用这个回调函数,并将一个整数作为参数传递给它。
my_callback
函数是一个简单的回调函数,它接受一个整数参数并打印出来。
在main
函数中,我们将my_callback
函数传递给do_something
函数,这样当do_something
函数完成其操作后,它会调用my_callback
函数。
? ? ? ? 运行结果:
2.3 C语言异步编程
? ? ? ? 回调函数在异步编程中有着重要的作用,在接口编程应用广泛,实战中经常会注册一个回调函数来接收其他程序返回的数据,这样做的好处是调用者无需主动去获取被调用者的数据,仅仅需要回调,让被调用者去传送数据,这样就形成了回调,这是回调最常见的应用。
? ? ? ? 假设A是视频流数据,每隔一段时间会将数据传送给B,B有两种接收方式:
? ? ? ? (1)A将视频数据存储好,提供接口,B根据自己的需求去调用,无需考虑时间,主动权在B。
? ? ? ? (2)A利用回调机制,实现回调函数,当数据来临时通知B来取数据,B注册回调函数接收数据,这样主动权在A。
? ? ? ? 很显然第一种取数据的方式,由于B不知道数据何时来临比较低效,而第二种取数据方式A通知B来取数据,效率比较高,间接的实现了中断取数。
? ? ? ? 这里就用到了回调,B注册一个函数,将函数地址传给A,A中调用该地址获取到B注册的函数时,我们就称这个函数为回调函数。
一个例子:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
// A的实现,一般会隐藏
typedef void (*CallbackPtr)(int); //函数指针定义
typedef struct parameter{
int a ;
CallbackPtr callback;
}parameter;
// 创建实例
parameter ParaData;
void* callback_thread(void *p1)//此处用的是一个线程
{
//do something
// 循环改变p->a的值为为0 2 3 4 5 6 7 8 9 ,每隔3秒改变一次
parameter* p = (parameter*)p1 ;
while(1)
{
sleep(3);//延时3秒执行callback函数
p->callback(p->a);//函数指针执行函数,这个函数来自于应用层B
p->a = (p->a + 1) % 10;
}
}
void startup_app_A()
{
// 初始化为0
ParaData.a = 0;
CallbackPtr init_call_back;
ParaData.callback = init_call_back;
//创建线程
pthread_t thing1;
pthread_create(&thing1,NULL,callback_thread,(void *) &ParaData);
}
// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr callback)
{
printf("SetCallBackFun print! \n");
ParaData.callback = callback;
}
// //-----------------------应用者B-------------------------------
void fCallBack(int a) // 应用者增加的函数,此函数会在A中被执行
{
//do something
printf("B得到A的数据 = %d\n",a);
}
int main(void)
{
// 启动A
startup_app_A();
SetCallBackFun(fCallBack);
// 主函数
while (1)
{
// std::cout << "main function" << std::endl;
printf("main function\n");
sleep(2);
}
return 0;
}
? ? ? ? 运行结果:
? ? ? ? 分析结果,可以看出A提供的数据会回调B,B会每隔一定的时间收到数据,完成回调,对于一般的编程会将A的操作封装起来,只提供以下接口和函数指针类型:
typedef void (*CallbackPtr)(int);
extern void SetCallBackFun(CallbackPtr callback);
? ? ? ? 这样B可以每次注册回调函数获取A传来的数据,如下:
void fCallBack(int a) // 应用者增加的函数,此函数会在A中被执行
{
//do something
printf("B得到A的数据 = %d\n",a);
}
? ? ? ? 主函数中调用:
SetCallBackFun(fCallBack);
? ? ? ? 这样就完成了一个C语言回调的异步编程,这在驱动领域极其常见,比如摄像头输出50fps的UVC流,程序员用UVC来完成相应的任务,这样就可以使用异步回调的方式实现。
🌈我的分享也就到此结束啦🌈
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
📢未来的富豪们:点赞👍→收藏?→关注🔍,如果能评论下就太惊喜了!
感谢大家的观看和支持!最后,?祝愿大家每天有钱赚!!!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!