VC++深入详解里面说得也挺好:回调函数的实现机制:

1)定义一个回调函数

2)“函数实现者”(回调函数所在的模块)在初始化的时候,将回调函数的函数指针注册给“调用者”。

3)当特定的事件或条件发生的时候,“调用者”使用函数指针调用“回调函数”对事件进行处理。

针对Windows的消息处理机制,窗口过程函数(回调函数)被调用的过程如下:

1)在设计窗口类的时候,将窗口过程函数的地址赋值给lpfnWndProc成员变量

2)调用RegisterClass(&wndclass)注册窗口类,那么系统也就有了上面的窗口过程函数的地址了。

3)当应用程序接收到某一窗口消息时,调用DispatchMessage(&msg)将消息回传给系统。系统则调用窗口过程函数(通过指针)对消息进行处理。

网友一例子对我很有启发,下面先看网页对回调函数的理解:

    其实回调就是一种利用函数指针进行函数调用的过程.   
    
为什么要用回调呢?比如我要写一个子模块给您用, 来接收远程socket发来的命令.当我接收到命令后, 需要调用您的主模块的函数,
来进行相应的处理.但是我不知道您要用哪个函数来处理这个命令,  
我也不知道您的主模块是什么.cpp或.h, 或说, 我根本不用关心您在主模块里怎么处理他, 也不应该关心用什么函数处理他......
怎么办?

使用回调.
    
我在我的模块A里先定义回调函数类型, 连同回调函数指针.
    
typedef void (CALLBACK *cbkSendCmdToMain) (AnsiString sCmd);
    
cbkSendCmdToMain    
SendCmdToMain;
    
这样SendCmdToMain就是个指向拥有一个AnsiString形参, 返回值为void的函数指针.
    
这样, 在我接收到命令时, 就能够调用这个函数啦. [Page]
    
...
     A_SendCmdToMain(sCommand);
    
...
    
但是这样还不够, 我得给一个接口函数(比如Init), 让您在主模块里调用A_Init来注册这个回调函数.
    
在您的主模块B里, 可能这样声明回调函数,
    
void CALLBACK YourSendCmdFun(AnsiString
sCmd);   //声明
    
...
    
void CALLBACK YourSendCmdFun(AnsiString
sCmd);   //定义
    
{
        
ShowMessage(sCmd);
    
}
    
...
    
调用A_Init函数向我的模块注册回调.可能这样:
     A_Init(YourSendCmdFun, ...);
    
这样, 预期目的就达到了.

需要注意一点, 回调函数一般都要声明为全局的. 假如要在类里使用回调函数, 前面需要加上
static   , 其实也相当于全局的.

 
 换种说法:
    “调用者”相当于win7系统;”回调函数“相当于软件的窗口响应函数,它会对鼠标的不同操作做出相应的响应。比如拖动计算器标题栏会移动窗口,双击计算器标题栏会无响应;拖动画板标题栏会移动窗口,双击画板标题栏时会全屏显示窗口。
    ”调用者“自己不会做”回调函数“的具体实现,它管不了日益增多的用户自定义软件,它只负责调用接口,具体怎么做要看软件们自己的思想了。
    “调用者”会在某一时刻用到“回调函数”,因为单击双击这些操作是鼠标在win7系统最常见的功能。
    “调用者”与“回调函数”的对接点是:”回调函数“指针,之所以使用函数指针,还是上面所说的优点,使用它可以对所有软件的某些消息做统一管理,屏幕掉同操作不同响应这些实现细节。
    对接点的入口我们称之为:”回调函数“注册函数,win7系统通过这个注册函数可以拿到回调函数指针,利用它就可以进行相应的响应操作。
下面是我的理解,希望你也能理解:

案例:

A方现在正在做一个项目,项目当中有一个任务交给了B方,让B方代理完成,但是在B执行代理任务期间却需要添加一些只有A方才有的专利信息,

所以这时候A方就要派本方一个专利接口人以协助B方,A方把专利方面的规则交待给这个专利接口人,B方执行代理任务期间遇到合适的机会时就会按专利接口人的要求打上A方定制的专利信息。

解释:

如果A只是单单把任务交给B方代理,自己不搀和进去的话,就很简单了,就如同我们调用printf函数一样,简单调用就可以直接完工。这种情况就是我们最常用的普通函数调用。

而现在的情况是:要在B方的代理任务里面需要添加一些A方专利,所以这里就发生了A调用B,B调用A,相互调用的情形:

A方调用B方的对接接口来完成任务,当B方在对接接口里用到专利函数时,就会回过头来调用A所提供的专利函数,所以就个专利函数就是我们所说的回调函数。

或者说:

回调函数就是一个挂靠函数,各位有意见吗?它就是让你写一个函数,写完后挂靠(Register)到调用者的系统或模块中,当调用者准备使用的时候,就拿过来用(使用函数指针)。

回调函数注定是要被调用者调用的,因为它的出现就是基于被调用者的需求而来的,所以它占的作用比较重要,而普通函数则不然,非必须的。

常见的实现有两种方式:

1,指定专利函数,调用对接接口(带专利函数参数)

A方调用B方的接口函数,由于接口函数本身附带专利函数信息,所以B方可以直接拿来使用,可按要求完成任务。

2,先注册专利函数,再调用对接接口(不带专利函数)

A方调用B方的注册函数,把将A方的专利函数注册到B方。

A方调用B方的接口函数,B方利用已经注册过专利函数,可按要求完成任务。

例子:

##################dll.h##################

#pragma once

#include "stdio.h"

//回调函数类型声明
typedef void (* CALLBACK)(int ); //实现方式一
extern void StartPrint(CALLBACK fun, int interval); //实现方式二
extern void RegisterPrint(CALLBACK fun);
extern void StartPrint(int interval);

##################dll.cpp##################

#include "dll.h"

CALLBACK g_pcb = NULL;

void StartPrint(CALLBACK fun, int interval)
{
RegisterPrint(fun);
for (int i=0; i<interval; i++) (g_pcb)(i);
} void RegisterPrint(CALLBACK fun)
{
g_pcb = fun;
} void StartPrint(int interval)
{
for (int i=0; i<interval; i++) (g_pcb)(i);
}

##################app.cpp##################

#include <stdio.h>
#include "dll.h" //回调函数定义1:A模块定义,提供给B模块,被B模块调用
void PrintHello(int i)
{
printf("[PrintHello]: Hello-%d\n", i);
} //回调函数定义2
void PrintBye(int i)
{
printf("[PrintBye]: Bye-%d\n", i);
} int main(int argc, char **argv)
{
//注册
RegisterPrint(&PrintHello);
//调用
StartPrint(5); //注册调用合并:好面熟哦,在这里你有没有看到线程创建函数的影子?
StartPrint(&PrintBye, 3);
return 0;
}

运行结果:

[PrintHello]: Hello-0
[PrintHello]: Hello-1
[PrintHello]: Hello-2
[PrintHello]: Hello-3
[PrintHello]: Hello-4
[PrintBye]: Bye-0
[PrintBye]: Bye-1
[PrintBye]: Bye-2
请按任意键继续. . .

回调函数的应用误区4(c/s OK版本回调小程序)的更多相关文章

  1. 嵌入式&iOS:回调函数(C)与block(OC)回调对比

    学了OC的block,再写C的回调函数有点别扭,对比下区别,回忆记录下. C的回调函数: callBack.h 1).定义一个回调函数的参数数量.类型. typedef void (*CallBack ...

  2. 理解 JavaScript 回调函数并使用

    JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...

  3. 关于js的回调函数的一点看法

    算了一下又有好几个月没写博客了,最近在忙公司android的项目,所以也就很少抽时间来写些东西了.刚闲下来,我就翻了翻之前看的东西.做了android之后更加感觉到手机端开发的重要性,现在做nativ ...

  4. C++ 回调函数的定义与用法

    一回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...

  5. javascript 函数初探 (四)--- 回调函数

    回调函数 既然函数与任何被赋值给变量的数据是相同的,那么她当然可以像其他数据那样被定义.删除.拷贝,以及当成参数传递给其它函数. 我们定义一个函数,这个函数有两个函数类型的参数,然后他会分别执行这两个 ...

  6. JS回调函数全解析教程

    转自:http://blog.csdn.net/lulei9876/article/details/8494337 自学jQuery的时候,看到一英文词(Callback),顿时背部隐隐冒冷汗.迅速g ...

  7. 浅谈js回调函数

    回调函数原理: 我现在出发,到了通知你”这是一个异步的流程,“我出发”这个过程中(函数执行),“你”可以去做任何事,“到了”(函数执行完毕)“通知你”(回调)进行之后的流程 例子 1.基本方法 ? 1 ...

  8. nodejs回调函数

    阻塞代码实例: main.js var fs=require("fs"); var data=fs.readFileSync("1.txt"); console ...

  9. 学习js回调函数

    <!DOCTYPE HTML> <html> <head> <meta charset="GBK" /> <title> ...

随机推荐

  1. sp_MSforeachtable使用方法 查看库中所有表的空间大小

    sp_MSforeachtable使用方法 1)说明系统存储过程sp_MSforeachtable和sp_MSforeachdb,是微软提供的两个不公开的存储过程,从ms sql 6.5开始.存放在S ...

  2. DllImport的具体用法

    现在是更深入地进行探讨的时候了.在对托管代码进行 P/Invoke 调用时,DllImportAttribute 类型扮演着重要的角色.DllImportAttribute 的主要作用是给 CLR 指 ...

  3. Lua 简单的IO交互 和迷宫代码

    function room1 () print("in room1") local move = io.read() if move == "south" th ...

  4. LightOj 1096 - nth Term (矩阵快速幂,简单)

    题目 这道题是很简单的矩阵快速幂,可惜,在队内比赛时我不知什么时候抽风把模版中二分时判断的 ==1改成了==0 ,明明觉得自己想得没错,却一直过不了案例,唉,苦逼的比赛状态真让人抓狂!!! #incl ...

  5. MQTT之 Mosquitto hello world的使用

    服务端发布消息模式,客户端订阅: 终端一中启动 moquitto 服务器 shallbeThatIshallbe:mosquitto iamthat$ 1427293344: Opening ipv4 ...

  6. 缓存初解(四)---Ibatis的缓存配置+Ehcache

    项目完结,整理一些技术方面的相关收获. 已经记不得EhCacheController这个实现类最早来自于那里了,总之稍加修改后非常有效果,大家就这么用了,感谢最初开源的那位兄弟.这里,主要是做个记录, ...

  7. Hibernate逍遥游记-第12章 映射值类型集合-002映射Bag(<idbag><collection-id>)

    1. 2. <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate ...

  8. NPOI操作EXCEL----------NPOI基础01

    来源地址:http://www.cnblogs.com/csqb-511612371/p/4878059.html 先来介绍一下NPOI基本的东西: 1.下载地址:http://npoi.codepl ...

  9. mybatis和hibernate区别和应用场景

    hibernate:是一个标准ORM框架(对象关系映射).入门门槛较高的,不需要程序写sql,sql语句自动生成了. 对sql语句进行优化.修改比较困难的. 应用场景: 适用与需求变化不多的中小型项目 ...

  10. Java NIO原理图文分析及代码实现

    原文: http://weixiaolu.iteye.com/blog/1479656 目录: 一.java NIO 和阻塞I/O的区别      1. 阻塞I/O通信模型      2. java ...