C++学习之回调函数

本文深入介绍了回调函数的概念,通过实例展示了如何在C语言中使用回调函数。回调函数是一种函数指针调用机制,使得函数在特定事件发生时被调用,而调用者与被调用者相互独立。同时,文章对比了回调函数与普通函数调用的区别,并详细解析了同步和异步回调的原理及其实现方式。最后,通过C和C++代码示例,演示了同步和异步回调的实际运用。
摘要由CSDN通过智能技术生成

参考:https://blog.csdn.net/qawsedrf123lala/article/details/119176116 代码修改为windows下可运行

1、什么是回调函数

回调函数就是通过函数指针调用函数。如果把函数的指针或者地址作为参数传递给另一个参数,当这个指针被用来调用其所指向的函数时,那么这就是一个回调的过程,这个被回调的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或者条件发生时由另外的一方调用的,用于对该事件或者条件进行响应。回调函数就是在两个独立函数或者独立类通信的通道。

回调函数是利用函数指针来实现的一种调用机制,学过GUI程序设计技术的同学肯定知道,回调函数还是GUI程序设计的底层技术。

回调机制原理:

1.调用者不知道具体事件发生时需要调用的具体函数

2.被调函数不知道何时被调用,只知道需要完成的任务

3.当具体事件发生时,调用者通过函数指针来调用具体函数

回调机制中的调用者和被调函数互不依赖。
例子:我们经常在电视剧或者电影中看到如下情节,一位主人公为了完成某个非常难的任务,这个时候一个绝世高人给了他一个锦囊,对他说你在遇到困难的时候打开这个锦囊,这个锦囊里面写的东西会告诉你怎么做。其实这里面就蕴含了回调的机制在里面。为什么呢?就比如我们把主人公去某个地方完成任务比作一个函数(调用者),然后锦囊里面的内容为一个函数(被调用者)。看看满不满足上述的3个条件。1.主人公不知道锦囊里面的内容,2.锦囊不知道什么时候会被主人公拆开,锦囊里面只写着怎么帮助主人公解决困难。3.当主人公遇到困难的时候,主人公通过打开锦囊来解决困难。
来看一个C语言程序加深大家对回调函数的理解。

#include <stdio.h>

typedef int(*Weapon)(int);

void fight(Weapon wp,int arg)
{
     printf("Fight Boss!\n");
     int result=0;
     
     result=wp(arg);
     
     printf("Boss Loss=%d\n",result);
}

int knife(int n)
{
    int ret=0;
    int i=0;
    
    for(i=0;i<n;i++)
    {
        printf("knife attack:%d\n",1);
        ret+=1;
    }
    
    return ret;
}

int sword(int n)
{
    int ret=0;
    int i=0;
    
    for(i=0;i<n;i++)
    {
       printf("Sword attack:%d\n",5);
       ret+=5;
    }
    
    return ret;
}

int gun(int n)
{
    int ret=0;
    int i=0;
    
    for(i=0;i<n;i++)
    {
        printf("Gun attack:%d\n",10);
        ret+=10;
    }
    
    return ret;
}

int main()
{
    fight(knife,5);
    fight(sword,5);
    fight(gun,5);
    
    return 0;
}

1.fight(wp,arg)函数和knife(n),sword(n),gun(n)他们之间互不依赖,只有当在主函数mian()中调用这3句代码的时候fght(knife,5);fight(sword,5);fight(gun,5);他们之间才通过函数指针产生联系。

2、回调函数和普通函数的区别

  • 对普通函数的调用:调用程序发出对普通函数的调用后,程序执行立即转向被调用函数执行,直到被调用函数执行完毕后,再返回调用程序继续执行。从发出调用的程序的角度看,这个过程为“调用–>等待被调用函数执行完毕–>继续执行”。
  • 对回调函数调用:调用程序发出对回调函数的调用后,不等函数执行完毕,立即返回并继续执行。这样,调用程序执和被调用函数同时在执行。当被调函数执行完毕后,被调函数会反过来调用某个事先指定函数,以通知调用程序:函数调用结束。这个过程称为回调(Callback),这正是回调函数名称的由来。

3、同步回调和异步回调的区别

  • 回调可以是同步也可以是异步
  • 同步可以是单线程也可以是多线程
  • 异步必须是多线程或多进程(每个进程可以是单线程) ==> 换句话说,异步必须依靠多线程或多进程才能完成

(1) 同步回调:把函数b传递给函数a。执行a的时候,回调了b,a要一直等到b执行完才能继续执行;

(2) 异步回调:把函数b传递给函数。执行a的时候,回调了b,然后a就继续往后执行,b独自执行。

4. 同步回调的实现

实现效果:

在这里插入图片描述

代码如下:

// CallbackTest1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// C代码实现的同步回调函数

#include "pch.h"
#include <iostream>
#include<stdio.h>
#include<string.h>

// C函数:回调函数
int RemoteControl(const char *actions[], int actions_len)
{
	printf("C回调函数被调用.    ==>  你朋友通过你开的 ***远程控制*** 操作你的电脑.\n");
	for (int i = 0; i < actions_len; i++) 
	{
		printf(">> %s\n", actions[i]);
	}
	printf("C回调函数返回.       ==>  处理完毕,退出远程的使用.\n");
	return 0;
}

// B函数
int YourFriend(int RControl(const char *actions[], int actions_len))
{
	// actions是提供的一些动作
	const char *actions[] = { "右键计算机",
					 "选择属性",
					 "选择高级系统设置",
					 "... ..."
	};
	printf("B函数被调用.    ==>  你朋友收到你的求助.\n");
	RControl(actions, 4); // 回调函数的执行
	printf("B函数返回.      ==>  你朋友向你反馈处理结果.\n");
	return 0;
}

// A函数
int You() 
{
	printf("A函数启动.      ==>  你用电脑,遇到了问题.\n");
	printf("A函数调用B函数.  ==>  你向你朋友发起求助,同时提供 ***远程控制*** 给他.\n");
	YourFriend(RemoteControl);
	printf("A函数返回.    ==>  你出门办事.\n");
	return 0;
}

int main() 
{
	You();
	return 0;
}

5、异步回调的实现

异步回调必定是多线程或者多进程的,不可能是单线程或者单进程的。
示例如下:
在这里插入图片描述
代码如下:

// CallbackProj.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"

#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include<thread>
#include<iostream>
#include<Windows.h>
#include "workThread.h"

using namespace std;


uint32_t OnDoWork(const std::vector<workParam>& vecWorkParam)
{
	for (auto pram : vecWorkParam)
	{
		printf("username:%s \n", pram.username);
		printf("time:%d \n", pram.begin_time);
		printf("price:%d \n", pram.end_time);
	}
	return 0;
}

int main(int argc, char *args[])
{
	workThread work;
	work.GetCallbackData(OnDoWork);
	//system("pause");
	printf("The main Thread is over! \n");

	return 0;
}

子线程类如下:

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include<unordered_map>
#include<thread>
#include<Windows.h>

struct workParam
{
	char username[10];
	uint32_t begin_time;
	uint32_t end_time;
};

typedef uint32_t(*CallFun)(const std::vector<workParam>& vecParam);

class workThread
{
public:
	workThread();
	~workThread();

	static workThread& GetInstance();
	void Init();
	void OnRun();
	void Realese();

	uint32_t  GetCallbackData(CallFun call_fun);
private:
	std::thread m_workThread;
	CallFun m_callFun;
	std::vector<workParam> m_vecParams;
	std::unordered_map<uint32_t, CallFun> m_mapFun;
};



#include "pch.h"
#include "workThread.h"

workThread::workThread()
{
	
}

workThread::~workThread()
{
	Realese();
}

workThread& workThread::GetInstance()
{
	static workThread threadImp;
	return threadImp;
}

void workThread::Init()
{
	workParam params;
	strncpy_s(params.username, "000001", sizeof(params.username));
	params.begin_time = 12345;
	params.end_time = 8888;
	m_vecParams.push_back(params);

	strncpy_s(params.username, "000002", sizeof(params.username));
	params.begin_time = 54454;
	params.end_time = 4444;
	m_vecParams.push_back(params);

	strncpy_s(params.username, "000003", sizeof(params.username));
	params.begin_time = 96875;
	params.end_time = 6666;
	m_vecParams.push_back(params);

	m_workThread = std::thread(std::bind(&workThread::OnRun, this));
}

void workThread::OnRun()
{
	printf("Child thread start successful! \n");
	Sleep(1000);
	m_mapFun[1](m_vecParams);
}

void workThread::Realese()
{
	if (m_workThread.joinable())
	{
		m_workThread.join();
	}
}

uint32_t workThread::GetCallbackData(CallFun call_fun)
{
	Init();
	m_mapFun[1] = call_fun;

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧特克_Glodon

很高兴能帮助到您!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值