如何使用C++回调函数
声明函数指针
回调函数是一个程序猿不能显式调用的函数;通过将回调函数的地址传给调用者从而实现调用。要实现回调,必须首先定义函数指针。虽然定义的语法有点不可思议,但假设你熟悉函数声明的一般方法,便会发现函数指针的声明与函数声明非常相似。请看以下的样例:
void f();// 函数原型
上面的语句声明了一个函数,没有输入參数并返回void。那么函数指针的声明方法例如以下:
void (*) ();
让我们来分析一下,左边圆括弧中的星号是函数指针声明的关键。另外两个元素是函数的返回类型(void)和由边圆括弧中的入口參数(本例中參数是空)。注意本例中还没有创建指针变量-仅仅是声明了变量类型。眼下能够用这个变量类型来创建类型定义名及用sizeof表达式获得函数指针的大小:
// 获得函数指针的大小
unsigned psize = sizeof (void (*) ());
// 为函数指针声明类型定义
typedef void (*pfv) ();
pfv是一个函数指针,它指向的函数没有输入參数,返回类行为void。使用这个类型定义名能够隐藏复杂的函数指针语法。
指针变量应该有一个变量名:
void (*p) (); //p是指向某函数的指针
p是指向某函数的指针,该函数无输入參数,返回值的类型为void。左边圆括弧里星号后的就是指针变量名。有了指针变量便能够赋值,值的内容是署名匹配的函数名和返回类型。比如:
void func()
{
/* do something */
}
p = func;
p的赋值能够不同,但一定要是函数的地址,而且署名和返回类型同样。
传递回调函数的地址给调用者
如今能够将p传递给还有一个函数(调用者)- caller(),它将调用p指向的函数,而此函数名是未知的:
void caller(void(*ptr)())
{
ptr(); /* 调用ptr指向的函数 */
}
void func();
int main()
{
p = func;
caller(p); /* 传递函数地址到调用者 */
}
假设赋了不同的值给p(不同函数地址),那么调用者将调用不同地址的函数。赋值能够发生在执行时,这样使你能实现动态绑定。
调用规范
到眼下为止,我们仅仅讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。很多编译器有几种调用规范。如在Visual C++中,能够在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默觉得_cdecl)。C++ Builder也支持_fastcall调用规范。调用规范影响编译器产生的给定函数名,參数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及參数传递机制(堆栈,CPU寄存器等)。
将调用规范看成是函数类型的一部分是非常重要的;不能用不兼容的调用规范将地址赋值给函数指针。比如:
// 被调用函数是以int为參数,以int为返回值
__stdcall int callee(int);
// 调用函数以函数指针为參数
void caller( __cdecl int(*ptr)(int));
// 在p中企图存储被调用函数地址的非法操作
__cdecl int(*p)(int) = callee; // 出错
指针p和callee()的类型不兼容,由于它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,虽然两者有同样的返回值和參数列。
如何使用C++回调函数的更多相关文章
- 小兔JS教程(三)-- 彻底攻略JS回调函数
这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...
- 嵌入式&iOS:回调函数(C)与block(OC)传 参/函数 对比
C的回调函数: callBack.h 1).声明一个doSomeThingCount函数,参数为一个(无返回值,1个int参数的)函数. void DSTCount(void(*CallBack)(i ...
- 嵌入式&iOS:回调函数(C)与block(OC)回调对比
学了OC的block,再写C的回调函数有点别扭,对比下区别,回忆记录下. C的回调函数: callBack.h 1).定义一个回调函数的参数数量.类型. typedef void (*CallBack ...
- 理解 JavaScript 回调函数并使用
JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...
- 关于js的回调函数的一点看法
算了一下又有好几个月没写博客了,最近在忙公司android的项目,所以也就很少抽时间来写些东西了.刚闲下来,我就翻了翻之前看的东西.做了android之后更加感觉到手机端开发的重要性,现在做nativ ...
- JS学习:第二周——NO.1回调函数
[回调函数] 定义:把一个函数的定义阶段,作为参数,传给另一个函数: 回调函数调用次数,取决于条件: 回调函数可以传参: 回调函数可以给变this指向,默认是window: 回调函数没有返回值,for ...
- 【java回调】java两个类之间的回调函数传递
背景交代:熟悉用js开发的cordovaAPP:对java一窍不通的我,老师让做一个监测用户拍照事件的功能,无奈没有找到现成的库,无奈自己动手开发java插件~~0基础java GreenHand,祝 ...
- Java|今天起,别再扯订阅和回调函数
编程史上有两个令人匪夷所思的说辞,一个是订阅,一个是回调函数. 我想应该还有很多同学为“事件的订阅”和“回调函数”所困扰,因为事情本来就不应该按这个套路来解释. 多直白,所谓的“回调函数”你完全可以线 ...
- C++ 回调函数的定义与用法
一回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...
- 通过修改i8042prt端口驱动中类驱动Kbdclass的回调函数地址,达到过滤键盘操作的例子
同样也是寒江独钓的例子,但只给了思路,现贴出实现代码 原理是通过改变端口驱动中本该调用类驱动回调函数的地方下手 //替换分发函数 来实现过滤 #include <wdm.h> #inclu ...
随机推荐
- 使用Caffe训练适合自己样本集的AlexNet网络模型,并对其进行分类
1.在开始之前,先简单回顾一下几个概念. Caffe(Convolution Architecture For Feature Extraction-卷积神经网络框架):是一个清晰,可读性高,快速的深 ...
- Ubuntu16.04下Hive的安装与配置
一.系统环境 os : Ubuntu 16.04 LTS 64bit jdk : 1.8.0_161 hadoop : 2.6.4mysql : 5.7.21 hive : 2.1.0 在配置hive ...
- IAR环境搭建注意点
1. include文件添加 Options->C/C++ Compiler 中的Preprocessor中增加一般的头文件 同时 在Assembler中的Preprocessor标签下添加$P ...
- Ext.example.msg()应用
①需要在开发包中包含文件夹example/shared中的example.js和example.css两个文件即可. ②在html文件中引入: <script src="../extj ...
- [js]正则篇
一.正则基本概念 1.一种规则.模式.文本处理工具 2.强大的字符串匹配工具 3.在js中常与字符串函数配合使用 二.js正则写法 正则在js中以正则对象存在: (1)var re=new RegEx ...
- OI回忆录(流水账)
今天是NOI2017疏散日,晚上回到家在电脑前写下这篇回忆录. 初中参加过几次普及组,拿过一等奖,自招进slyz. 高一参加过CTSC2016,狗牌滚粗qwq 高二参加过WC2017,CTSC2017 ...
- Android ContentObserver详解
前言: 工作中,需要开启一个线程大量的查询某个数据库值发送了变化,导致的开销很大,后来在老大的指点下,利用了ContentObserver完美的解决了该问题,感到很兴奋,做完之后自己也对Content ...
- Java并发(二十二):定时任务ScheduledThreadPoolExecutor
需要在理解线程池原理的基础上学习定时任务:Java并发(二十一):线程池实现原理 一.先做总结 通过一个简单示例总结: public static void main(String[] args) { ...
- Android 中点击返回键弹出“在按一次退出程序”的做法
在很多应用中都有这种做法,连续点击两次才退出程序,目的是为了防止用户不小心点击到了返回键而退出程序了,添加了一次用户确认的过程. 其实做法很简单,只需要做一个延时的消息处理就可以了. 首先在我们在一个 ...
- 洛谷P2746 USACO5.1 校园网
题目描述 一些学校连入一个电脑网络.那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作“接受学校”).注意即使 B 在 A 学校的分发列表中, A 也不一定在 B 学校的列表中. 你要写 ...