精华内容
下载资源
问答
  • 通过Qt控制台工程写了几个回调函数的例子,希望对初学者有帮助
  • C++回调函数详解

    2015-07-31 13:50:43
    我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理、用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函数)有何不同呢?...
  • c++回调函数应用,在通信编程中可能会使用的几率大一下,使用时现将函数调用的地址保存下来,然后在使用时直接调用之前保存的函数地址,即为回调
  • C++ 回调函数

    2014-01-21 11:53:06
    回调函数在编程中经常使用到,这个代码简单明了的呈现了C++使用回调函数的方法。
  • 主要介绍了C++回调函数详解及简单实例的相关资料,需要的朋友可以参考下
  • C++回调函数使用心得

    万次阅读 多人点赞 2018-11-11 15:23:52
    C++回调函数使用心得前言回调函数也是普通函数C回调函数C++回调函数使用场景描述C++回调函数定义静态成员函数访问非静态成员函数的方法回调对象更复杂的讨论 前言 关于C++回调函数的介绍网上有很多,要知道它的...

    前言

    关于C++回调函数的介绍网上有很多,要知道它的概念很容易,难的是灵活应用,这里就笔者遇到的一个使用场景对回调函数进行一个简单的介绍,如果能对您有所帮助是我的荣幸。本文不会对C++回调函数的基础知识做过多的介绍,若对其概念不够理解的,笔者在此推介两篇个人认为相当优秀的博客。
    链接: link1.
    链接: link2.

    回调函数也是普通函数

    首先明确一个概念,回调函数也是普通函数,而不是什么神秘的东西。至于为什么叫回调函数,是因为程序通过参数把该函数的函数指针传递给了其它函数,在那个函数里面调用这个函数指针就相当于调用这个函数,这样的过程就叫回调,而被调用的函数就叫回调函数。看得出来,回调的本质是函数指针传递,所以想要理解回调机制,先要理解函数指针。

    C回调函数

    C++回调函数扩展自C回调函数,要想理解C++回调函数,先要理解C回调函数。我们通过一个实例来讲解C回调函数的使用方法。

    //callbackTest.c
    //1.定义函数onHeight(回调函数)
    //@onHeight 函数名
    //@height   参数
    //@contex   上下文
    void onHeight(double height, void* contex)
    {
    	sprint("current height is %lf",height);
    }
    
    //2.定义onHeight函数的原型
    //@CallbackFun 指向函数的指针类型
    //@height      回调参数,当有多个参数时,可以定义一个结构体
    //@contex      回调上下文,在C中一般传入nullptr,在C++中可传入对象指针
    typedef void (*CallbackFun)(double height, void* contex);
    
    //3.定义注册回调函数
    //@registHeightCallback 注册函数名
    //@callback             回调函数原型
    //@contex               回调上下文
    void registHeightCallback(CallbackFun callback, void* contex)
    {
    	double h=100;
    	callback(h,nullptr);
    }
    
    //4.main函数
    void main()
    {
    	//注册onHeight函数,即通过registHeightCallback的参数将onHeight函数指针
    	//传入给registHeightCallback函数,在registHeightCallback函数中调用
    	//callback就相当于调用onHeight函数。
    	registHeightCallback(onHeight,nullptr);
    }

    程序的运行结果是:
    current height is 100
    很多时候,注册的时候并不调用回调函数,而是在其他函数中调用,那我们可以定义一个CallbackFun全局指针变量,在注册的时候将函数指针赋给它,在要调用的调用它。如

    //定义全局指针变量
    CallbackFun* m_pCallback;
    //定义注册回调函数
    void registHeightCallback(CallbackFun callback, void* contex)
    {
    	m_pCallback = callback;
    }
    //定义调用函数
    void printHeightFun(double height)
    {
    	m_pCallback(height,nullptr);
    }
    //main函数
    void main()
    {
    	//注册回调函数onHeight
    	registHeightCallback(onHeight,nullptr);
    	//打印height
    	double h=99;
    	printHeightFun(99);
    }

    程序的运行结果是:
    current height is 99

    C++回调函数

    C++回调函数扩展自C,与C略有不同的是,C++可以使用全局函数和静态函数作为回调函数。考虑到全局函数会破坏封装性,所以一般都用静态成员函数。故除了理解函数指针,还要理解静态成员函数,具体一点是在静态成员函数中访问非静态成员函数的方法,因为我们很可能需要获取静态成员函数中的数据。

    使用场景描述

    比如说你使用了别人提供的sdk,这个sdk可能来自供应商,也有可能来自你的同事,他就提供给你一个注册回调函接口,比如就下面这个,你可以通过回调函数获取到height(某种传感器的实时返回的数据),你要怎么做?

    C++回调函数定义

    //CallbackFun类型
    //@CallbackFun 指向函数的指针类型
    //@height      回调参数,当有多个参数时,可以定义一个结构体
    //@contex      回调上下文,在C中一般传入nullptr,在C++中可传入对象指针
    typedef void (*CallbackFun)(double height, void* contex);
    
    //注册回调函数接口
    //@registHeightCallback 注册函数名
    //@callback             回调函数原型
    //@contex               回调上下文
    void registHeightCallback(CallbackFun callback, void* contex)

    首先,你要定义一个静态成员函数并注册。

    //sensorTest.cpp
    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		cout << "current height is  " << height << endl;
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, this);
    	}
    };
    
    //main 函数
    void main()
    {
    	Sensor sens;
    	sens.registCallback();
    }

    运行程序,我们发现控制台一直在打印
    current height is **
    说明我们的回调函数正确实现了。到这一步不难,只要掌握基本的回调函数概念都能实现。
    现在我们有这样一种情况,我们有另外一个类,要在这个类里面实时打印获取的数据,要怎么做呢?

    静态成员函数访问非静态成员函数的方法

    我们知道静态成员函数中是只能出现静态变量和静态函数的,但是有些时候真的需要访问非静态成员函数或变量,比如我上面说的那种情况。让我们先来实现对同一个类中的非静态成员函数的访问。
    修改class Sensor如下

    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		//cout << "current height is  " << height << endl;
    		Sensor* sen = (Sensor*)contex;
    		if(sen)  //注意判断sen是否有效
    			sen->getHeight(height);
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, this);
    	}
    	//新增的成员函数
    	void getHeight(double height)
    	{
    		cout << "current height is  " << height << endl;
    	}
    };

    如此修改之后,得到与修改前一样的效果(实时打印height),关键点在于注册回调函数的时候将Sensor对象的指针传给了contex,在回调函数中又将contex转换为Sensor对象指针,所以能调用普通函数。
    同理,如果注册时传入某一个对象的指针,就可以在回调函数中对该对象进行操作,这就是我们可以在一个对象中回调另一个对象的思想。

    回调对象

    现在开始解决之前提出的问题,本质是不变的,回调是指针传递,可以是函数指针,也可以是对象指针。

    //先定义一个类class DataPrint
    //打印数据类class DataPrint
    class DataPrint{
    public:
    	DataPrint(){}
    	~DataPrint(){}
    	void printHeight(double height)
    	{
    		cout << "print height is " << height << endl;
    	}
    };
    
    //要在类Sensor中增加DataPrint的指针和一个DataPrint指针赋值函数,class Sensor修改为
    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		DataPrint* dp = (DataPrint*)contex;
    		if(dp)  //注意判断dp是否有效
    			dp->printHeight(height);
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, m_pDataPrint );
    	}
    	//新增的成员函数
    	void getHeight(double height)
    	{
    		//cout << "current height is  " << height << endl;
    	}
    	void setDataPrint(DataPrint* dp)
    	{
    		m_pDataPrint = dp;
    	}
    private:
    	DataPrint* m_pDataPrint;
    };
    
    //main主函数
    void main()
    {
    	DataPrint* dp=new DataPrint();
    	Sensor* sens=new Sensor();
    	//注意这两句的顺序不能颠倒
    	sens->setDataPrint(dp);
    	sens->registCallback();
    }

    这样就能实现在另一个类中取得回调函数的数据,如果无法保证DataPrint的实例化一定在Sensor之前,我们可以这样做

    //先定义一个类class DataPrint
    //打印数据类class DataPrint
    class DataPrint{
    public:
    	DataPrint(){}
    	~DataPrint(){}
    	void printHeight(double height)
    	{
    		cout << "print height is " << height << endl;
    	}
    };
    
    //要在类Sensor中增加DataPrint的指针和一个DataPrint指针赋值函数,class Sensor修改为
    //接收数据类class Sensor
    class Sensor{
    public:
    	Sensor(){}
    	~Sensor(){}
    	//定义回调函数onHeight
    	static void onHeight(double height, void* contex)
    	{
    		Sensor* sen= (Sensor*)contex;
    		if(sen)  //注意判断sen是否有效
    			sen->getHeight(height);
    	}
    	//定义注册回调函数
    	void registCallback()
    	{
    		registHeightCallback(onHeight, m_pDataPrint );
    	}
    	//新增的成员函数
    	void getHeight(double height)
    	{
    		if(m_pDataPrint )
    			m_pDataPrint ->printHeight(height);
    	}
    	void setDataPrint(DataPrint* dp)
    	{
    		m_pDataPrint = dp;
    	}
    private:
    	DataPrint* m_pDataPrint;
    };
    
    //main主函数
    void main()
    {
    	DataPrint* dp=new DataPrint();
    	Sensor* sens=new Sensor();
    	//注意这两句的顺序可以颠倒
    	sens->setDataPrint(dp);
    	sens->registCallback();
    }

    两个的区别是一个直接注册指定类的对象指针,另一个注册当前类的对象指针,间接调用另一个类的对象指针。

    更复杂的讨论

    刚才讨论的问题稍微复杂一点了,不过应该也容易理解,但是我们在实际项目中遇到的情况可能比这个复杂。比如在有层次的软件工程中,回调函数在底层,显示数据的类在上层,我们要如何把底层的数据显示到上层去?容易想到的是上层调用底层,如开个timer刷新,但这是不对的,你无法做到实时调用,你需要的是一个异步的机制,即底层一发生上层就能接收到。
    怎么做呢?还是一样的道理,把上层的类的对象指针传给底层,这时底层需要包含上层的头文件,但这是不对的,上层已经包含了底层的头文件,它们不能互相包含,如何解决这个问题?那就要用到C++继承的特性,首先在底层定义一个基类,然后在上层继承它,在上层实例化这个继承类后,将其指针设置给底层,底层对该指针的操作就是对继承类对象的操作,以此实现数据的传递。
    这里就不贴代码了,思想是这样的,很多情况下需要实际问题实际分析,欢迎讨论。

    展开全文
  • 主要介绍了C++回调函数(CallBack)的用法,较为详细的分析了C++回调函数(CallBack)的原理并以实例形式总结了其具体用法,具有一定参考借鉴价值,需要的朋友可以参考下
  • 主要介绍了C++回调函数及函数指针的实例详解的相关资料,希望通过本文能帮助到大家,让大家理解掌握这部分内容,需要的朋友可以参考下
  • 这里面有两个运用回调函数的DEMO程序 1.其中tcCallBack的作用是希望通过将Receiver类的成员函数注册到Call中, Call类的对象在合适的时候调用该回调函数实现运算或者传值。需要注意的是本DEMO需要提前在Call中声明...
  • C++回调函数

    2014-04-02 11:26:17
    C++中如何处理编写回调函数,什么是回调函数
  • C/C++回调函数介绍

    2021-01-01 10:12:27
    对于很多初学者来说,往往觉得回调函数很神秘,很想知道回调函数的工作原理。本文将要解释什么是回调函数、它们有什么好处、为什么要使用它们等等问题,在开始之前,假设你已经熟知了函数指针。 什么是回调函数? ...
  • 浅谈C++回调函数

    千次阅读 2018-02-28 22:09:30
    1.什么是回调函数? 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数回调函数不是由该函数的实现方...

      1.什么是回调函数?

           回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

          简单总结:什么是回调函数?——就是由声明函数的类来调用的函数叫做回调函数。普通函数可以让任何类调用。“回调”的主语是谁?——声明“回调函数”的那个类。Block、委托、通知、回调函数,它们虽然名字不一样,但是原理都一样,都是“回调机制”的思想的具体实现!

    2.回调函数的机制

          (1)定义回调函数原型;(2)提供函数实现的一方在初始化的时候,将回调函数注册给调用者;(3)当特定的事件或条件发生的时候,调用者使用函数指针调用函数对事件进行处理。

    3.回调函数的意义

           因为可以把调用者和被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

    4.回调函数的作用

           想知道回调函数在实际中有什么作用?先假设有这样一种情况:我们要编写一个库,它提供了某些排序算法的实现(如冒泡排序、快速排序、shell排序、shake排序等等),为了能让库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,能让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。

           回调可用于通知机制。例如,有时要在A程序中设置一个计时器,每到一定时间,A程序会得到相应的通知,但通知机制的实现者对A程序一无所知。那么,就需一个具有特定原型的函数指针进行回调,通知A程序事件已经发生。实际上,API使用一个回调函数SetTimer()来通知计时器。如果没有提供回调函数,它还会把一个消息发往程序的消息队列。

            再比如,假设有A、B两个类。
    (1)A类有多种形态,要在B类中实现回调函数。如假设A类是网络请求开源类ASIHttpRequest,它可能请求成功,也可能请求失败。这个时候,B类就要针对以上两个情况,作不同的处理。
    (2)A类的形态由B类决定时,要在B类中实现回调函数。如UITableView类就会提供很多回调函数(iOS专业术语称“委托”方法)

    (3)A类需要向B类传递数据时,可以在B类中实现回调函数(A类一般是数据层比较耗时的操作类)。如举的那个发工资的例子。在实际编程中,这样的机制有个好处就是可以提升用户的操作体验。比如用户从X页面跳转到Y页面,需要向网络请求数据,而且比较耗时,那我们怎么办?有三种方案:第一种就是在X页面展示一个旋转指示器,当收到网络传回的数据时,在展现Y页面。第二种就是使用回调函数。用户从X页面直接跳转到Y页面,Y页面需要到数据让数据层去执行,当收到数据时,再在Y页面展现。第三种就是在Y页面中开启多线程。让一个子线程专门到后台去取数据。综合来说,第二种更加简介易懂,而且代码紧凑。

             不管怎么说,回调函数是继承自C语言的。在C++中,应只在与C代码建立接口或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在C++中应使用虚方法或仿函数(functor),而不是回调函数。

    5.代码示例

            

    typedef int(__stdcall*CompareFunction)(constbyte*,constbyte*)

         它就是回调函数的类型,负责用同样的参数形式将参数传递给相应的具体元素比较函数。另外,通过它,两个不同的排序算法,可以调用和具体元素相关的比较函数,实现和元素类型无关的排序:Bubblesort()和Quicksort(),这两个方法都用同样的参数原型,但实现了不同的排序算法。

    void DLLDIR__stdcallBubblesort(byte*array,intsize,intelem_size,CompareFunctioncmpFunc);
    void DLLDIR__stdcallQuicksort(byte*array,intsize,intelem_size,CompareFunctioncmpFunc);
    这两个函数接受以下参数:
    ·byte * array:指向元素数组的指针(任意类型)。
    ·int size:数组中元素的个数。
    ·int elem_size:数组中一个元素的大小,以字节为单位。

    ·CompareFunction cmpFunc:带有上述原型的指向回调函数的指针。

    这两个函数都会对数组进行某种排序,但每次都需决定两个元素哪个排在前面,而函数中有一个回调函数,其地址是作为一个参数传递进来的。对编写者来说,不必介意函数在何处实现,或它怎样被实现的,所需在意的只是两个用于比较的元素的地址,并返回以下的某个值(库的编写者和使用者都必须遵守这个约定):
    ·-1:如果第一个元素较小,那它在已排序好的数组中,应该排在第二个元素前面。
    ·0:如果两个元素相等,那么它们的相对位置并不重要,在已排序好的数组中,谁在前面都无所谓。
    ·1:如果第一个元素较大,那在已排序好的数组中,它应该排第二个元素后面。

    基于以上约定,函数Bubblesort()的实现如下,Quicksort()就稍微复杂一点:

    void DLLDIR__stdcall Bubblesort(byte*array,intsize,intelem_size,cmpFunc)
    {
    for(inti=0;i<size;i++)
    {
    for(intj=0;j<size-i-1;j++)
    {
    //回调比较函数
    if(1==(*cmpFunc)(array+j*elem_size,array+(j+1)*elem_size))
    {
    //两个相比较的元素相交换
    byte* temp=newbyte[elem_size];
    memcpy(temp,array+j*elem_size,elem_size);
    memcpy(array+j*elem_size,array+(j+1)*elem_size,elem_size);
    memcpy(array+(j+1)*elem_size,temp,elem_size);
    delete[]temp;
    }
    }
    }
    }
    注意:因为实现中使用了memcpy(),所以函数在使用的数据类型方面,会有所局限。

    对使用者来说,必须有一个回调函数,其地址要传递给Bubblesort()函数。下面有二个简单的示例,一个比较两个整数,而另一个比较两个字符串:

    int__stdcall CompareInts(constbyte*velem1,constbyte*velem2)
    {
    int elem1=*(int*)velem1;
    int elem2=*(int*)velem2;
    if(elem1<elem2)
    return-1;
    if(elem1>elem2)
    return1;
    return0;
    }
    int __stdcall CompareStrings(constbyte*velem1,constbyte*velem2)
    {
    const char* elem1=(char*)velem1;
    const char* elem2=(char*)velem2;
    return strcmp(elem1,elem2);
    }

    下面另有一个程序,用于测试以上所有的代码,它传递了一个有5个元素的数组给Bubblesort()和Quicksort(),同时还传递了一个指向回调函数的指针。(使用byte类型需包含头文件windows.h,或:

    typedef unsignedchar bute;
    int main(intargc,char*argv[])
    {
    int i;
    int array[]={5432,4321,3210,2109,1098};
    cout<<"BeforesortingintswithBubblesort\n";
    for(i=0;i<5;i++)
    cout<<array[i]<<'\n';
    Bubblesort((byte*)array,5,sizeof(array[0]),&CompareInts);
    cout<<"Afterthesorting\n";
    for(i=0;i<5;i++)
    cout<<array[i]<<'\n';
    const char str[5][10]={"estella","danielle","crissy","bo","angie"};
    cout<<"BeforesortingstringswithQuicksort\n";
    for(i=0;i<5;i++)
    cout<<str[i]<<'\n';
    Quicksort((byte*)str,5,10,&CompareStrings);
    cout<<"Afterthesorting\n";
    for(i=0;i<5;i++)
    cout<<str[i]<<'\n';
    return0;
    }
    如果想进行降序排序(大元素在先),就只需修改回调函数的代码,或使用另一个回调函数,这样编程起来灵活性就比较大了。

    上面的代码中,可在函数原型中找到__stdcall,因为它以双下划线打头,所以它是一个特定于编译器的扩展,说到底也就是微软的实现。任何支持开发基于Win32的程序都必须支持这个扩展或其等价物。以__stdcall标识的函数使用了标准调用约定,为什么叫标准约定呢,因为所有的Win32 API(除了个别接受可变参数的除外)都使用它。标准调用约定的函数在它们返回到调用者之前,都会从堆栈中移除掉参数,这也是Pascal的标准约定。但在C/C++中,调用约定是调用者负责清理堆栈,而不是被调用函数;为强制函数使用C/C++调用约定,可使用__cdecl。另外,可变参数函数也使用C/C++调用约定。
    Windows操作系统采用了标准调用约定(Pascal约定),因为其可减小代码的体积。这点对早期的Windows来说非常重要,因为那时它运行在只有640KB内存的电脑上。

    如果你不喜欢__stdcall,还可以使用CALLBACK宏,它定义在windef.h中:

    #define CALLBACK__stdcallor
    #define CALLBACKPASCAL//而PASCAL在此被#defined成__stdcall
    作为回调函数的C++方法

    因为平时很可能会使用到C++编写代码,也许会想到把回调函数写成类中的一个方法,但先来看看以下的代码:

    class CCallbackTester
    {
    public:
    int CALLBACKCompareInts(constbyte*velem1,constbyte*velem2);
    };
    Bubblesort((byte*)array,5,sizeof(array[0]),&CCallbackTester::CompareInts);
    如果使用微软的编译器,将会得到下面这个编译错误:

    errorC2664:’Bubblesort’:cannotconvertparameter4from’int(__stdcallCCallbackTester::*)(constunsignedchar*,constunsigne)

    这是因为非静态成员函数有一个额外的参数:this指针,这将迫使你在成员函数前面加上static。

    6.使用回调函数的好处

    (1)可以让实现方,根据回调方的多种形态进行不同的处理和操作。(ASIHttpRequest)
    (2)可以让实现方,根据自己的需要定制回调方的不同形态。(UITableView)
    (3)可以将耗时的操作隐藏在回调方,不影响实现方其它信息的展示。
    (4)让代码的逻辑更加集中,更加易读。


    展开全文
  • C++ 回调函数(Qt系列)

    2021-01-07 15:57:08
    什么是回调函数? 就是以函数指针做参数传递给另一个函数称之为回调函数, 字面意思很简单, 但就这几个字想理解回调函数, 那又很难。因此别就这这字面意思, 只要知道怎么用, 在什么情况下用就行了 什么场景下...

    什么是回调函数?

    就是以函数指针做参数传递给另一个函数称之为回调函数, 字面意思很简单, 但就这几个字想理解回调函数, 那又很难。因此别就这这字面意思, 只要知道怎么用, 在什么情况下用就行了

    什么场景下需要使用回调函数

    回调函数主要是完成通知功能, 例如我领导给我分配另外工作, 但是我手里工作又没做完, 那领导总不可能没过个几个小时就跑过来问一下,这样我们两个人都很烦, 而在代码中如果这样实现(需要开一个线程, 不停的轮寻)也很消耗系统资源, 所以最好的办法就是等我手里的工作完成了, 我自己去和领导说,然后进入下个工作任务, 而在我们代码中想要这样实现就需要通过回调函数来完成


    回调函数3要素:

    • 定义一个函数指针(和回调函数的参数类型,数量,顺序,返回值全部一致)。
    • 定义一个类成员静态回调函数(备注:类成员回调函数必须是static)。
    • 回调函数和函数指针绑定在一起。

    回调函数用法1: C98回调函数写法

    //该类相当于上面例子中员工(我)的角色
    
    using namespace std;//定义一个函数指针
    typedef void(*PrintName)(string strName);
    
    enum CallType
    {
    	NAME,
    	AGE,
    	GRADE,
    };
    
    class CallBack
    {
    public:
    	CallBack();
    	~CallBack();
    public:
    	void TestCallBack(CallType type);
    public:
    	PrintName m_PrintName;
    };
    
    #include <memory>
    #include "CallBack.h"
    class BaseCall
    {
    public:
        BaseCall();
        ~BaseCall();
     
    public:
            //静态的类成员函数
        static void onPrintName(string strName);
    private:
        std::shared_ptr<CallBack> m_CallBack;
    };
     
    BaseCall::BaseCall()
    {
        m_CallBack = make_shared<CallBack>();
            //和回调函数绑定
        m_CallBack->m_PrintName = onPrintName;
        m_CallBack->TestCallBack(NAME);
    }
     
    BaseCall::~BaseCall()
    {
     
    }
     
    void BaseCall::onPrintName(string strName)
    {
        printf("姓名: %s\n", strName.c_str());
    }
    

    Qt 中的回调函数

    而在Qt中传数据,我们是使用信号槽系统,但这并不意味着不能使用旧的经过验证的方法,即使用 CallBack回调函数功能。
    事实上使用 CallBack 功能比信号和槽要快一些。并且当发送信号的对象在程序中被销毁并且不再使用时,就信号理想地从槽中分离而言,回调可以更容易使用。

    假设A类包含B类的对象,B类有动作时想要通知到A类,B类应该有个设置回调函数的接口,A类应该定义相应的回调函数,将函数指针传递给B。

    展开全文
  • C++回调函数作为通信机制

    千次阅读 2019-05-18 17:05:17
    回调函数特别适合实现类之间的通信. 类之间的通信, 不同的平台有各自的解决方案, 比如windows有MFC, 这里面就包含大量的回调函数机制, 保证类之间的通信. 这里, 实现一个自定义的回调函数机制, 进行基础的通信. 问题...

    回调函数特别适合实现类之间的通信. 类之间的通信, 不同的平台有各自的解决方案, 比如windows有MFC, 这里面就包含大量的回调函数机制, 保证类之间的通信. 这里, 实现一个自定义的回调函数机制, 进行基础的通信.

    问题背景:
    有一个服务器的类, 服务器有一系列的客户端的集合. 是否断开与服务器的连接由客户端决定. 如果客户端申请断开连接, 那么服务器就要把需要断开链接的客户端从集合中进行清理. 这里就面临一个问题, 申请断开的是客户端, 而执行清理的是服务器, 但是客户端无法直接执行服务器的清理工作. 唯一能做的是, 通知服务器进行清理.

    思路:
    服务器单独定义一个函数用于清理指定的客户端, 然后把这个函数作为回调函数传递个客户端, 保存为函数对象的类型. 客户端请求断开连接时, 执行服务器的这个函数对象即可.

    注意, 这里说的客户端是RPC意义上的客户端, 这么抽象是为了方便程序设计, 这也是C\S架构常用的一个方法.

    代码中注意一个地方, 我们需要保证回调的时候, 是删除的断开连接的函数, 因此在Client内部重载比较函数. 因为使用智能指针, 在堆内存上开辟, 所以使用内存地址的比较, 这是唯一的定位符.

    代码实例:

    #include <iostream>
    #include <functional>
    #include <set>
    #include <memory>
    
    class Client {
    public:
        void set_cbfunc(std::function<void()> f) {
            m_cbFunc = std::move(f);
        }
    
        void callback() {
            std::cout << "client callback id: " << id << std::endl;
            m_cbFunc();
        }
    
        // 比较函数, 仅仅是为了区分确定的客户端, 方便在容器中比较
        inline bool operator<(const Client &client) {
            return bool(this < &client);
        }
    
        inline int getId() const {
            return id;
        }
    
        inline void setId(int id_) {
            id = id_;
        }
    
    private:
        int id;
        std::function<void()> m_cbFunc;
    };
    
    
    class Server {
    public:
        void callback(std::shared_ptr<Client> &p) {
            std::cout << "Server callback, id: " << p->getId() << std::endl;
            m_pClients.erase(p);
        }
    
        void start() {
            std::cout << "Before CallBack, Client num: " << m_pClients.size() << std::endl;
            for (auto &p: m_pClients) {
                std::cout << "client id: " << p->getId() << std::endl;
                p->callback();
            }
            std::cout << "After CallBackClient num: " << m_pClients.size() << std::endl;
        }
    
        std::set<std::shared_ptr<Client>> m_pClients;
    };
    
    int main() {
        Server server;
        for (int i = 0; i < 5; ++i) {
            auto it = std::make_shared<Client>();
            it->setId(i);
            it->set_cbfunc(std::bind(&Server::callback, &server, it));
            server.m_pClients.insert(it);
        }
        server.start();
        return 0;
    }
    

    输出结果:

    Before CallBack, Client num: 5
    client id: 0
    client callback id: 0
    Server callback, id: 0
    client id: 3
    client callback id: 3
    Server callback, id: 3
    client id: 1
    client callback id: 1
    Server callback, id: 1
    client id: 4
    client callback id: 4
    Server callback, id: 4
    client id: 2
    client callback id: 2
    Server callback, id: 2
    After CallBackClient num: 0
    

    可以看出, 成功删除了断开链接的客户端, 而且3次确认都是删除正确的.

    展开全文
  • C#委托与C++回调函数处理

    热门讨论 2010-01-30 23:24:50
    告诉你怎么用C#委托处理dll中的回调函数。有几篇文档在里面
  • c++ 回调函数与std::function使用实例

    千次阅读 2019-12-12 16:47:36
    实际项目中,经常有使用回调函数的需求,如: 双方通信中,等待接收对方的数据并处理,如使用socket进行的TCP通信 定时器事件,当定时器计时结束时,需要处理某任务 信号的触发,需要执行某任务 在同步编程中,...
  • 回调函数,使用c++做的例子,适用于多线程领域
  • 本文主要介绍C++回调函数中调用类中的非静态成员变量或非静态成员函数 回调函数中调用类中的非静态成员变量或非静态成员函数 【问题】如何在类中封装回调函数? a.回调函数只能是全局的或是静态的。 b.全局函数会...
  • c++ 回调函数示例

    千次阅读 2018-08-29 17:48:41
    #include &lt;stdio.h&gt; //函数指针,定义一个函数指针的原型,名称为:lpFunc,三个参数:...//调用回调函数的宿主函数,参数callback是原型名称为lpFunc的函数指针 void GetCallBack(void *lpVoid,lpF...
  • 最简单的C/C++回调函数实现

    千次阅读 2018-12-05 18:39:34
    回调函数,就是一个通过函数指针调用的函数。如果你把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,这就是回调函数回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件...
  • C++回调函数.pdf C++回调函数.pdf C++回调函数.pdf mfc c++
  • C++ 回调函数理解

    万次阅读 多人点赞 2015-12-18 13:49:55
    编程中肯定会遇到在C++中使用回调函数的情况。 但是为什么要使用回调函数呢?我们需要理解回调函数设计原理 因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定...
  • C++回调函数的基本理解和使用

    万次阅读 多人点赞 2018-05-30 17:34:06
    回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数回调函数不是由该函数的实现方直接调用,而是在特定...
  • C++将类的成员函数作为回调函数使用介绍
  • C++ 回调函数的实现,以及function,bind,lambda表达式的使用传统回调方法使用函数指针使用接口类使用模板 传统回调方法 常见的回调函数实现方式。 以下转自: https://www.cnblogs.com/kanite/p/8299147.html ...
  • 2.回调函数 什么是回调函数呢?回调函数其实就是一个通过函数指针调用的函数!假如你把A函数的指针当作参数传给B函数,然后在B函数中通过A函数传进来的这个指针调用A函数,这就是回调机制。B函数就是回调函数。 3....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,989
精华内容 42,795
关键字:

c++回调函数

c++ 订阅