首页

文章

回调函数的实现

发布网友 发布时间:2022-04-19 20:08

我来回答

1个回答

热心网友 时间:2022-04-19 02:11

代码实现
下面创建了一个sort.dll的动态链接库,它导出了一个名为CompareFunction的类型-- typedefint(__stdcall*CompareFunction)(constbyte*,constbyte*)它就是回调函数的类型,负责用同样的参数形式将参数传递给相应的具体元素比较函数。另外,通过它,两个不同的排序算法,可以调用和具体元素相关的比较函数,实现和元素类型无关的排序:Bubblesort()和Quicksort(),这两个方法都用同样的参数原型,但实现了不同的排序算法。 voidDLLDIR__stdcallBubblesort(byte*array,intsize,intelem_size,CompareFunctioncmpFunc);voidDLLDIR__stdcallQuicksort(byte*array,intsize,intelem_size,CompareFunctioncmpFunc);这两个函数接受以下参数:
·byte * array:指向元素数组的指针(任意类型)。
·int size:数组中元素的个数。
·int elem_size:数组中一个元素的大小,以字节为单位。
·CompareFunction cmpFunc:带有上述原型的指向回调函数的指针。
这两个函数都会对数组进行某种排序,但每次都需决定两个元素哪个排在前面,而函数中有一个回调函数,其地址是作为一个参数传递进来的。对编写者来说,不必介意函数在何处实现,或它怎样被实现的,所需在意的只是两个用于比较的元素的地址,并返回以下的某个值(库的编写者和使用者都必须遵守这个约定):
·-1:如果第一个元素较小,那它在已排序好的数组中,应该排在第二个元素前面。
·0:如果两个元素相等,那么它们的相对位置并不重要,在已排序好的数组中,谁在前面都无所谓。
·1:如果第一个元素较大,那在已排序好的数组中,它应该排第二个元素后面。
基于以上约定,函数Bubblesort()的实现如下,Quicksort()就稍微复杂一点: void DLLDIR__stdcallBubblesort(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 byte;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*,constunsignedchar*)’to’int(__stdcall*)(constunsignedchar*,constunsignedchar*)’Thereisnocontextinwhichthisconversionispossible这是因为非静态成员函数有一个额外的参数:this指针,这将迫使你在成员函数前面加上static。

历史要怎么读,有啥诀窍 高中历史诀窍 年终会活动策划方案 深度解析:第一财经回放,探索财经新风向 逆水寒手游庄园怎么邀请好友同住 逆水寒手游 逆水寒不同区可以一起组队吗? 逆水寒手游 逆水寒怎么进入好友世界? 逆水寒手游 逆水寒怎么去别人的庄园? 使用puppeteer实现将htmll转成pdf 内卷时代下的前端技术-使用JavaScript在浏览器中生成PDF文档 【译】将HTML转为PDF的几种实现方案 变形金刚08动画怎么样 变形金刚08动画的问题 变形金刚08动画日语版剧情介绍 高分!换显卡nvidia控制面板被我卸了,重新安装显卡驱动后没了nvidia控... 我的nvidia控制面板被卸载了 怎么找回啊 卸载后 这个画面看着很奇怪_百 ... 李卓彬工作简历 林少明工作简历 广东工业职业技术学院怎么样 郑德涛任职简历 唐新桂个人简历 土地入股的定义 ups快递客服电话24小时 贷款记录在征信保留几年? 安徽徽商城有限公司公司简介 安徽省徽商集团新能源股份有限公司基本情况 安徽省徽商集团有限公司经营理念 2019哈尔滨煤气费怎么有税? 快手删除的作品如何恢复 体育理念体育理念 有关体育的格言和理念 什么是体育理念 万里挑一算彩礼还是见面礼 绿萝扦插多少天后发芽 绿萝扦插多久发芽 扦插绿萝多久发芽 炖牛排骨的做法和配料 网络诈骗定罪标准揭秘 “流水不争先”是什么意思? mc中钻石装备怎么做 为什么我的MC里的钻石块是这样的?我想要那种。是不是版本的问题?如果是... 带“偷儿”的诗句 “君不见巴丘古城如培塿”的出处是哪里 带“奈何”的诗句大全(229句) 里翁行()拼音版、注音及读音 带“不虑”的诗句 “鲁肃当年万人守”的出处是哪里 无尘防尘棚 进出口报关流程,越详细越好。谢谢大家指教。 双线桥不是看化合价升多少就标多少的吗?为什么CL2+2KI=2KCL+I2中I失... 函数名作为参数传递与回调函数 回调函数实现通知机制这个怎么理解 jquery中的回调函数怎么用 PHP中的回调函数是怎么实现的? 什么是"回调"在C和它们是如何实现的 PHP中的回调函数是怎么实现的? C++中回调函数的如何实现其逻辑? C++回调函数原理 举个简单的小程序例子 回调函数 钩子函数 有什么区别 php回调函数是什么样子的?靠什么原理运行? c#-回调callback是什么原理,机制? C# C++回调函数原理举个简单的小程序例子 回调函数一般都什么作用求解 回调函数(callback)是什么? ,, 关于回调函数的详细讲解 回调函数是怎么实现的?为什么系统就会去调用回调函数 在拼多多上两个人怎么拼单啊 用呼吸作用的原理分析为什么刚采摘下来的苹果最好吃? 人体吸入氧气呼出二氧化碳,这是基于什么原理? 举例说明呼吸作用原理在日常生活中如何被应用 请问使用回调函数,在接收数据的时候就可以不用判... 讲解如何实现C#回调函数 拼多多上面怎么拼单,毕竟喜欢同一件商品的人很少,QQ群上面拼多多互相砍价群,靠谱吗?请知道的说一说 如何为他人挂号? 怎样在我的手机上给别人挂号挂什么挂? 怎么样可以在微信上给家人预约挂号 南京鼓楼医院在手机上绑定家庭成员后怎么帮家人预... 怎样帮别人在我的手机上给别人挂沈阳医大的号 医院的预约号可以帮别人预约挂号吗? 怎样在我的手机上给别人挂沈阳医大的号 华西医院的微信公众号上怎么帮家人挂号 怎么在手机上挂号预约 拼多多商家如何设置拼单人数? 运维工程师以后的发展方向有哪些? IT运维工程师发展前景如何? 做系统运维工程师有前途吗 网络运维就业前景如何? 运维工程师这个职位有前途吗 运维工程师以后发展情况怎么样呢? IT运维工程师发展前景如何
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com