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. 140227项目开发及上线过程遇到的10个问题(重点: FCK过滤替换)

    1.替换条件判断问题 String s = (String)map2.get("contentIntro"); if(s != null && s.length() ...

  2. Cloud Insight 仪表盘上线 | 全面监控 Redis

    OneAPM 作为应用性能领域的新兴领军企业,近期发布了重量级新产品-- Cloud Insight 数据管理平台,用它能够监控所有基础组件,并通过 tag 标签对数据进行管理. 近日,Cloud I ...

  3. ubuntu 13.10 64bit装BeyondCompare

    1. Beyond Compare官网下载amd-64位的,安装失败,依赖于ia32-libs,但是这个文件已经不在源里了: 2. 官网下载tar.gz源码包,解压安装失败: 3. 直接装32位的,可 ...

  4. Python中Lambda, filter, reduce and map 的区别

    Lambda, filter, reduce and map Lambda Operator Some like it, others hate it and many are afraid of t ...

  5. Java文件解压之TGZ解压

    package com.alibaba.intl.batch.dependency; import java.io.File; import java.io.FileInputStream; impo ...

  6. 65. Valid Number

    题目: Validate if a given string is numeric. Some examples:"0" => true" 0.1 " = ...

  7. NSArray 初始化

    //NSArray长度不可变所以初始化的时候就赋值,并且最后以nil结尾 //此外需要注意NSArray不能存放C语言的基础类型 NSObject *obj=[[NSObject alloc]init ...

  8. Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.

    在部署的时候出现Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server ...

  9. [HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 这题以前做过…现在用tarjan搞一发…竟然比以前暴力过的慢………… 由于是离线算法,需要Que ...

  10. JAVA中获取工程路径的方法

    在jsp和class文件中调用的相对路径不同.在jsp里,根目录是WebRoot 在class文件中,根目录是WebRoot/WEB-INF/classes 当然你也可以用System.getProp ...