c++回调

C++回调方式的实现 回调在我们开发的过程种使用的频率非常之高。甚至有这样一种说法,开发者会不会使用回调直接就能看出这个人的开发能力,回调的使用几乎会存在任何的项目中。最近在用C++开发项目刚好要用到回调,等到需要使用的时候才发现和C语言的回调使用方式完全不是一回事(以前主要写C),也是查找了一番资料才慢慢搞懂C++回调的一些常用用法。在此做一个简要的总结记录,避免日后忘记后有个可以翻阅的地方,也和各位码友分享,有不足之处欢迎在评论区批评指正,一起成长!废话不多说,直接进入主题吧。 在回答为什么要用回调函数之前,我 阅读详情

前言

嵌入式中经常使用到回调事件,比如生产者生产数据后将数据回调到消费者的缓存中,这里面涉及到2个技术,一个是回调, 另外一个是数据的并发和同步, 本主题主要讲回调。


c中的使用

这个比较简单, 因为没有涉及到数据的封装,或者说作用域都是public吧,比如struct之类的。

c++中的使用

方案1:使用static方式

该方式和c中一致, 如果代码做到高聚低耦,可以用注册的方式比较好。

方案2:使用c++11中的function以及bind

方案3:使用::方式

方案4:使用callback(datafunc pf, void *pUserData);

代码

代码有贴出了方案2和方案3的测试demo,使用非常方便

./a.out  1
其中1表示使用::的方式, 2表示function+bind方式 

header

#ifndef MY_BIND_H__
#define MY_BIND_H__

#include <vector>
#include <functional>
#include <iostream>
#include <memory>

struct srcImagData
{
    char *data;

    unsigned int  siz;
    srcImagData():data(nullptr), siz(0){}

};

class CTest
{
public:
	typedef std::vector<srcImagData> DataVec;
	static CTest* inst()
	{
		static CTest ct;return &ct;
	}
	
    void dataCB( const srcImagData &lhs_data);
    
    void show() const 
    {
		for(const auto &x : *data_)
		{
			std::cout << "siz: " << x.siz << std::endl;
		}
    }

	std::function<void(srcImagData&)> callback_data_; 
private:
	CTest();
	~CTest();
    std::shared_ptr<DataVec> data_;
};




#endif 

src

#include "bind.h"


CTest::CTest():data_( new DataVec )
{
	callback_data_ = std::bind(&CTest::dataCB, this, std::placeholders::_1);
}
CTest::~CTest(){

	auto it = data_->begin();
	for(;it != data_->end(); ++it)
	{
		if(it->data) 
		{
			free(it->data); it->data = nullptr;
			it->siz = 0;
		}
	}
	std::cout << "Done." << std::endl;
}

 void CTest::dataCB(  const srcImagData &lhs_data)
{
#if 0
	if(lhs_data.data)
	{
		std::cout << "data nullptr" << std::endl;
		return ;
	}
#endif

	data_->push_back(lhs_data);
	
}


#if 1

enum 
{
	CallBack_static = 0x00,		//该方式比较简单, 不做程序展示, 和c中非封装的差不多
	CallBack_used_pulic ,	
	CallBack_function		//推荐
};

int main(int argc, char *argv[])
{
	if(argc < 2)
	{
		std::cout << "Usage: " << argv[1] <<  " 0" << std::endl;
		return -1;
	}

	int sel = atoi(argv[1]);
	using namespace std::placeholders;		//adds visibility of _1, _2, _3,...
    
	switch(sel)
	{ 
		case CallBack_used_pulic:
		{
			void (CTest::*pTestFunc4)(const srcImagData& );  
			pTestFunc4 = &CTest::dataCB;
			for(int i = 0; i< 10; i++)
			{
				srcImagData t;
				//do somethings ... TODO: e.g malloc image data 
				//释放在析构中释放
				t.siz = 100 * i;
				(CTest::inst()->*pTestFunc4)(t);
			}

			CTest::inst()->show();
		}break;
		case CallBack_function:
		{
			srcImagData t;
		
			for(int i = 0; i < 10; i++)
			{
				//
				t.siz = 100*i;
				CTest::inst()->callback_data_(t);
			}
			
			CTest::inst()->show();
		}break;
		
			
	
	}
   	return 0;
}

#endif 

代码II:

/**
		注册: 注册时带方法地址 + 类方法的实例指针
		调用:  将数据到push到注册的实例中,同时将实例的地址图传给实调用者
		
		该方式兼容了c的接口, 针对模块设计为第三方的,使用c的方式的回调接口,如果
		使用的是c++的接口, 可以通过std::functional中的std::bind()更好
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread>
#include <string>
#include <iostream>
#include <string.h>
#define BUF_MAX		(1024)

typedef struct MyStruct
{
	char buf[BUF_MAX];
	
	
}MyStruct_S;

typedef void (*datafunc)(const MyStruct_S  *pData, void *pUserData);

/*注册端*/
class CMyClass
{
public:
	CMyClass();
	~CMyClass();
	/*注意第二个形参的意思, 主要是静态方法中无法使用类的数据和方法*/
	static void requestCB(const MyStruct_S*, void*);
	
	int setMyStructData(const MyStruct_S *pMyData);
private:
	//datafunc dataCallback_;
	MyStruct_S myStructData_;
	
};

CMyClass::CMyClass(){}

CMyClass::~CMyClass(){}

int CMyClass::setMyStructData(const MyStruct_S *pMyData)
{
	if(pMyData)
	{
		printf("%s.\n", pMyData->buf);return -1;
		memcpy(&myStructData_, pMyData,  sizeof(MyStruct_S));
	}
	
}

void CMyClass::requestCB(const MyStruct_S *pdata, void *pUserData)
{
	

	if(!pdata || !pUserData)
	{
		printf("nullptr\n");return ;
		
	}
	CMyClass *pinst = (CMyClass*)pUserData;
	pinst->setMyStructData(pdata);
	
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
	反注册模块, 一般是数据的生产者或响应者,注意setCallback方法的第二个参数的意义
*/
class CMoudleClass
{
public:
	CMoudleClass();
	~CMoudleClass();
	
	void dataCreaterProc();
	void setCallback(const datafunc pf, void *); 	/*注册*/
	
private:
	bool isRun_;
	std::thread *pdataThread_;		//数据生产者
	MyStruct_S myStructData_;
	
	datafunc datacb_;
	void *pUserdata_;		/*注册端的数据*/
	
};

CMoudleClass::CMoudleClass():pdataThread_(nullptr), isRun_(true), datacb_(nullptr), pUserdata_(nullptr)
{
	pdataThread_ = new std::thread(&CMoudleClass::dataCreaterProc, this);
	if(nullptr == pdataThread_)
	{
		printf("create thread failure .\n");
		
	}
}


CMoudleClass::~CMoudleClass()
{
	isRun_ = false;
	if(pdataThread_ )
	{
		if( pdataThread_->joinable()) pdataThread_ ->join();
		delete pdataThread_; pdataThread_ = nullptr;
	}
	
}
/*
	@brief   地址填充 
	@params[in]		pf - 调用者的地址   pUserData - 调用者的实例地址
	@return   null 
	
*/
void CMoudleClass::setCallback(const datafunc pf, const void *pUserData)
{
	datacb_ = pf;  
	pUserdata_ = pUserData;
	
}


void CMoudleClass::dataCreaterProc()
{
	while(isRun_)
	{
		static int cnt = 0;
		if(datacb_)
		{
			memset(&myStructData_, 0, sizeof(MyStruct_S));
			snprintf(myStructData_.buf, BUF_MAX-1, "%08d", ++cnt);
			datacb_(&myStructData_, pUserdata_);
			sleep(1);
			
		}else{sleep(2);}
	}
	
}


int main(int argc, char *argv[])
{
	CMyClass myclassInst;
	
	
	CMoudleClass cModuleInst;
	cModuleInst.setCallback(myclassInst.requestCB, (void*)&myclassInst);
	
	while(1)
	{
		
		sleep(3);
	}
	
	
}
在C++实现回调 来看看怎么在C++中实现回调吧。Method1:使用全局函数作为回调在C语言中的回调很方便。当然,我们可以在C++中使用类似于C方式的回调函数,也就是将全局函数定义为回调函数,然后再供我们调用。typedef void(*pCalledFun)(int *);void GetCallBack(pCalledFunparafun){/*do something*/}如果我们想使用GetCallBack函数,那么就要实现一个pCalledFun类型的回调函数:void funCallback(int *iNum 阅读详情

相关推荐

C++中的回调函数

一、回调机制 1.回调定义(小A带着名片D通过途径C找到小B求他帮忙,小B不能立即解决于是收下名片D,之后的某天小B解决了小A的问题后又通过名片D告诉了小A解决方法) 2.回调方法: ①定义一个函数(普通函数即可);②将此函数的地址注册给调用者;③特定的事件或条件发生时,调用者使用函数指针调用回调函数。例如: 二、同步回调和异步回调 举例:假设有两个程序员在写代码,A程序员写底层...

qq_34754747的博客 2485

C++回调函数使用心得

C++回调函数使用心得前言回调函数也是普通函数C回调函数C++回调函数使用场景描述C++回调函数定义静态成员函数访问非静态成员函数的方法回调对象更复杂的讨论 前言 关于C++回调函数的介绍网上有很多,要知道它的概念很容易,难的是灵活应用,这里就笔者遇到的一个使用场景对回调函数进行一个简单的介绍,如果能对您有所帮助是我的荣幸。本文不会对C++回调函数的基础知识做过多的介绍,若对其概念不够理解的,笔者...

sinat_38183777的博客 2万+

C++回调的几种方式

自己平时常用到的C++回调方式主要为两类 通过设置函数指针的方式 通过集成接口的方式(Sink下沉) 一. 设置接口sink的方式 一般都是由一个消息接口类,作为回调,需要处理返回回调的信息的类,只需要继承接口类,并实现对应的方法即可。初始化时,只需要将子类设置下去,待任务完成时,就可以实现回调。 简单的模仿一下文件传输,ITaskCallback为消息回调接口,需要该消息回调的类,只需要继承...

Code_Hu的博客 1167

C++ 委托与回调进阶使用

摘要:本文探讨了C++中委托和回调函数的应用机制。委托通过std::function实现函数类型抽象,使函数能像变量一样传递,提升代码灵活性、解耦性和可扩展性。回调函数则实现了控制反转,将特定动作交由外部触发。文章通过数学运算示例展示了委托参数传递,并构建了一个完整的消息处理系统演示回调机制,包括字符串解析、验证逻辑和多重回调注册等场景,强调在异步编程中需注意对象生命周期管理。

平平无奇的小甜菜 1320

Ubuntu20.04下Pycharm的快速安装与配置指南

本文提供了一份详细的Ubuntu 20.04系统下PyCharm社区版的安装与配置指南。文章重点介绍了通过手动下载.tar.gz压缩包进行安装的灵活方法,并涵盖了系统准备、依赖安装、首次运行、创建快捷方式以及解释器配置等关键步骤,帮助Python开发者快速搭建高效、可控的本地开发环境。

weixin_28831341的博客 379

SAP IDOC实战:如何用EDI实现跨公司采购订单自动生成销售订单(附完整配置步骤)

本文详细解析了如何利用SAP IDOC与EDI技术,实现跨公司采购订单自动生成销售订单的完整流程。通过实战案例,从业务蓝图设计、输出条件配置、伙伴参数设定到IDOC消息类型处理,提供了清晰的配置步骤与故障排查指南,帮助企业打通内部业务流,构建高效的自动化闭环。

weixin_29215815的博客 727

c++ 回调函数的注册与调用学习

结合自己项目的使用:登记注册于调用。

老赵的博客 1932

Python+gensim【中文LDA】简洁模型

文章目录完整代码过程详解words_lsdictionarydictionary.doc2bow函数corpuslda 完整代码 from gensim import corpora, models import jieba.posseg as jp # 待分析文本集 text1 = '美国教练坦言,没输给中国女排,是输给了郎平' text2 = '中国女排世界排名第一?真实水平如何,听听巴西和美...

ArYe 2万+

C++实现回调实例(附带源码)

C++实现回调实例(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1268

Fluent DPM模型保姆级教程:三通管颗粒流动模拟,从网格导入到轨迹图生成

本文提供Fluent DPM模型在三通管颗粒流动模拟中的保姆级教程,涵盖从网格导入到轨迹图生成的全流程。通过详细步骤和参数设置,帮助用户掌握DPM模型在颗粒流动模拟中的关键技巧,适用于化工、能源等领域的工程应用。

weixin_30615767的博客 578

Fortigate 在AWS中配置HA

方案1: 1、将两台服务器配置在相同可用区中,使用飞塔原生HA功能,可以实现配置同步功能。 2、配置SSLVPN,在主服务器不可用时,可以实现自动切换到备用服务器继续提供VPN服务。 当前问题: 1、主挂掉后可以自动切换到备,但是原主服务器修复后不会自动切换到主状态。 2、如下图所示切换中丢包明显,需要客户端开启“保持连接”功能。 配置过程如下: 1、整体架构 2、创建VPC和子网,如下图所示...

子苏蓝莓的博客 891

C/C++ 回调函数的使用

之前看公司代码发现一处用法,类似于这样的typedef void(*Callback)(int, double, std::string);一般C++11以后是这么定义的 std::function func;后来才知道这就是传说中的回调函数用的,一般是C语言用的比较多,C++有自己的方法.

m0_38036750的博客 1344

从一个 ASIN 看透亚马逊:商品模型背后的增长飞轮

在亚马逊电商体系中,每件商品背后都有一套严密的商品建模逻辑。本篇文章以“ASIN 的一生”为线索,系统拆解了亚马逊的商品模型:从飞轮战略出发,剖析 SDP(Single Detail Page)机制如何实现标准化展示;再到 ASIN 编码、父子变体结构与 Offer 分离模型,逐层解析商品信息如何被建构、聚合与呈现。通过图解与案例,文章帮助读者理解商品建品流程、同款聚合原则、价格控制机制等核心逻辑,避免常见运营误区,是一份面向运营、产品、技术人员的实用参考指南。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 13万+

C++11较为优雅的回调函数写法

管理类 所有的子模块都注册在这个类 这个类使用单例模式 使用回调来通知子模块 .h #pragma once #include "GUI.h" #include "logic.h" #include <functional> #include <iostream> #include <queue> #include <vector> #include...

qq_40843445的博客 2222

Windows系统下载安装 Git 的详细教程

本文详细介绍了Windows系统下载安装Git的完整流程,包括从Git官方网站和阿里镜像下载安装包,逐步讲解安装向导中的各个设置选项,如安装路径、默认编辑器、行尾转换、终端模拟器等,并提供了每个步骤的截图和说明。安装完成后,博客还介绍了如何验证安装是否成功,以及如何配置Git的用户名和邮箱,确保可以正常使用Git进行版本控制。

加斯顿工程师的博客 795

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java调用C++,并在C++中回调Java

Java调用C++,并在C++中回调Java MainActivity.java文件: package com.mytest.j2c; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; public class MainActivity extends AppCompatActivity { // Used to load

Flying_Motor的博客 1251

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

深入 C++ 回调

许多面试官会问:你知道回调吗?你在写回调的时候遇到哪些坑?你知道对象生命周期管理吗?为什么这里会崩溃,那里会泄漏? 在设计 C++ 回调时,你是否想过:同步还是异步?回调...

腾讯技术工程 1749

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

C++回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 回调函数机制: 1、定义一个函数(普通函数即可); 2、将此函数的地址注册给调用者; 3、特定的事件或条件发生时,调用者使用函数指针调用回调函数。 C回调函数 C++回调函数扩展自C回调函数,要想理解C++回调函数,先要理解C回调函数。我们通过

lovely_yoshino的博客 6992

C++回调C#

C++回调C# 现在比较流行C#与C++融合:C#做GUI,开发效率高,C++做运算,运行效率高,二者兼得。但是C++与C#必然存在数据交互,C#与C++dll的数据交互从来都是一个让人头疼的问题。 从调用方式看也有两种情况: 1、C#调用C++函数 这种情况用的比较多,数据流向可以是C#流向C++,通过参数将数据传递给C++(如:SetData(double[] data));也可以是C++流向C#(如:GetData(double[] data))。 2、C++ Callback ..

jacberg的专栏 2316

C/C++回调方式系列之二class接口回调和lambda程式

在《C/C++回调方式系列之一》中我们总结了函数指针模式回调,这些回调当时比较原始,容易给人一种面向过程的编程的感觉,而且函数指针的格式比较繁琐,可读性相对差一点。本系列二将总结比较推荐的回调使用模式。 一、class接口回调模式 1. 定义接口 C++可以定义virtual纯虚类作为函数接口类, 例如定义 Introducer接口 class Introducer { public:

SweetTool的专栏 4194

CPP类之间的回调函数

回调就是一种利用函数指针进行函数调用的过程. 通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。回调的价值在于它的灵活性,可以在运行时动态的决定需要调用什么方法。引用一段话: 使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。 以下例子在VS2008中调试通过 #incl...

丰空岛主(Vega Prime,Android,LabWindows,ThreeJS,Python,OpenCV) 928

C++的注册和回调

注册回调的作用   在设计模式中注册回调的方式叫做回调模式。在SDK开发中,为增强开发者的SDK通用性,排序或者一些算法逻辑需要使用者进行编写。这时候就需要向SDK传递回调函数。注册回调能使下层主动与上层通信。从而避免了上层不停询问下层的模式。 注册回调的流程   SDK的接口会提供一个注册回调函数,来规范回调函数的格式,如返回值,参数等。使用者编写一个固定格式的回调函数,来调用SDK提供的...

weixin_30782293的博客 2661

C++中的回调

关于回调,在C++ 面向对象里面好像并没有什么比较被关注,感觉比较弱化的一个概念,但是从作为从C开发过来的人,对于回调并不陌生,这么重要的一种方式在c++中怎么没有提及?至少很少见到设置回调的,这次就回调这个思想就在c++ 里面谈一下个人的见解: C开发,被划分为面向过程式开发,也就是遵照计算机的顺序执行 方式开发,但有的时候编写一个函数,希望这个函数执行到某一个结果时就处理一个特定的任务 比如...

Canok 1215

CPP类回调函数示例

#include class CServer { public: typedef void (CServer::*FN_CALLBACK)(void); CServer() { m_pCallback = NULL; m_fnCallback = NULL; } void BindCallback(void* pCallback, FN_CALL

tjv001的专栏 910

C++ 异步回调

上一文中讲了C语言通过函数指针实现异步回调 本文继续讨论C++中实现回调,由于C++中有类,而C语言中的回调函数不能直接定义为成员函数,所以就很麻烦了,下面将讨论解决办法。 首先知道静态成员函数是全局的,也就是类的,因此推测可以用静态成员函数来实现回调机制。这里补充一下关于类中静态成员的知识#include <iostream> #include <stdio.h> #include <stdl

夏菠 1万+
上一篇: nvidia设置wifi和接口
下一篇: GStreamer第一阶段的简单总结
帘下有白绿
博客等级 码龄12年 165粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值