当前位置:   article > 正文

C++学习之回调函数_c++回调的原理

c++回调的原理

参考: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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

子线程类如下:

#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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/162491
推荐阅读
相关标签
  

闽ICP备14008679号