- 浏览: 145195 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
hxl860217:
...
为什么要使用代理类(代理模式) -
showzh:
myeclipse没有这个菜单
如何卸载Eclipse插件 -
xiefei3k:
不给力啊 从数据里查出用户名的结果里面进行判断的代码呢。
...
jquery servlet jsp完成用户名存在验证 $.ajax() -
songfantasy:
不错。挺好的。
如何卸载Eclipse插件 -
tongliaozhang:
只适合数字吧 如果有汉字怎么办呢我的第一列中有A01 这样的记 ...
利用PL/SQL Developer工具导入excel数据
回调函数,就是由你自己写的。你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。
typedef int (__stdcall *PFunc)(int, int); int __stdcall Max(int a, int b) { return a > b ? a : b; } int __stdcall Test(PFunc func, int a, int b) { return func(a, b); } void main() { cout << Test(Max, 1, 30) << endl; }
就是: 不是你直接调用的函数 而是 系统/或者其他地方调用的
比如 如果是API需要传入回调函数 那么就是API里面调用这个回调函数
如果是你自己的函数调用 。。那么同样了 比如 上面的代码。
=======================================================================
在C#中,委托的作用是这样描述的:委托就像一个函数的指针,在程序运行时可以使用它们来调用不同的函数。这个其实和你委托同事完成 JS代码一样。如果有两位同事可以做这件事情,他们只要做的结果能够满足你的需求(就像一个接口),尽管他们做的过程不一样,并且作出的效果也不一样,但是,能够达到你的要求就可以了。
=======================================================================
软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础。
对于不同类型的语言(如结构化语言和对象语言)、平台(Win32、JDK)或构架(CORBA、DCOM、WebService),客户和服务的交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。
对于一般的结构化语言,可以通过回调函数来实现回调。回调函数也是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数。
在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象C++或Object Pascal这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。
Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。
对于分布式组件代理体系CORBA,异步处理有多种方式,如回调、事件服务、通知服务等。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理过程,我们可以通过回调机制来实现。
下面我们集中比较具有代表性的语言(C、Object Pascal)和架构(CORBA)来分析回调的实现方式、具体作用等。
2 过程语言中的回调(C)
2.1 函数指针
回调在C语言中是通过函数指针来实现的,通过将回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针,请看下面的例子:
void Func(char *s);// 函数原型
void (*pFunc) (char *);//函数指针
可以看出,函数的定义和函数指针的定义非常类似。
一般的化,为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。
typedef void(*pcb)(char *);
回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。
被调函数的例子:
void GetCallBack(pcb callback)
{
/*do something*/
}
用户在调用上面的函数时,需要自己实现一个pcb类型的回调函数:
void fCallback(char *s)
{
/* do something */
}
然后,就可以直接把fCallback当作一个变量传递给GetCallBack,
GetCallBack(fCallback);
如果赋了不同的值给该参数,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。
2.2 参数传递规则
到目前为止,我们只讨论了函数指针及回调而没有去注意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,尽管两者有相同的返回值和参数列
2.3 应用举例
C语言的标准库函数中很多地方就采用了回调函数来让用户定制处理过程。如常用的快速排序函数、二分搜索函数等。
快速排序函数原型:
void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
二分搜索函数原型:
void *bsearch(const void *key, const void *base, size_t nelem,
size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
其中fcmp就是一个回调函数的变量。
下面给出一个具体的例子:
#include <stdio.h>
#include <stdlib.h>
int sort_function( const void *a, const void *b);
int list[5] = { 54, 21, 11, 67, 22 };
int main(void)
{
int x;
qsort((void *)list, 5, sizeof(list[0]), sort_function);
for (x = 0; x < 5; x++)
printf("%i\n", list[x]);
return 0;
}
int sort_function( const void *a, const void *b)
{
return *(int*)a-*(int*)b;
}
2.4 面向对象语言中的回调(Delphi)
Dephi与C++一样,为了保持与过程语言Pascal的兼容性,它在引入面向对象机制的同时,保留了以前的结构化特性。因此,对回调的实现,也有两种截然不同的模式,一种是结构化的函数回调模式,一种是面向对象的接口模式。
=======================================================================
http://dev.csdn.net/develop/article/20/20778.shtm
我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理、用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函数)有何不同呢?这里结合自己的使用经历做一个简单的介绍。
使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。至于如何定义回调函数,跟具体使用的API函数有关,一般在帮助中有说明回调函数的参数和返回值等。C++中一般要求在回调函数前加CALLBACK(相当于FAR PASCAL),这主要是说明该函数的调用方式。
至于钩子函数,只是回调函数的一个特例。习惯上把与SetWindowsHookEx函数一起使用的回调函数称为钩子函数。也有人把利用VirtualQueryEx安装的函数称为钩子函数,不过这种叫法不太流行。
也可以这样,更容易理解:回调函数就好像是一个中断处理函数,系统在符合你设定的条件时自动调用。为此,你需要做三件事:
1. 声明;
2. 定义;
3. 设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用。
声明和定义时应注意:回调函数由系统调用,所以可以认为它属于WINDOWS系统,不要把它当作你的某个类的成员函数
http://www.china-askpro.com/msg25/qa03.shtml
使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。至于如何定义回调函数,跟具体使用的API函数有关,一般在帮助中有说明回调函数的参数和返回值等。C++中一般要求在回调函数前加CALLBACK,这主要是说明该函数的调用方式。DialogBox的回调函数实际上是个窗口过程,用来处理所有消息。其定义为:
BOOL CALLBACK DialogProc(
HWND hwndDlg, // handle of dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
在Win32 API中有详细说明。一般使用C++ Builder或MFC的往往没有使用SDK编程的经验,建议找一些SDK编程的书看一下,否则很难理解如何使用窗口过程。
至于钩子函数,只是回调函数的一个特例。习惯上把与SetWindowsHookEx函数一起使用的回调函数称为钩子函数。也有人把利用VirtualQueryEx安装的函数称为钩子函数,不过这种叫法不太流行。
Top
回复人:useresu(俗人)(努力做翻译ing) ( 一星(中级)) 信誉:100 2005-6-8 16:50:36 得分:10
?
回调一般是在函数参数中声明一个函数指针,随其他函数参数一起传入(参数一般是指针类型传址),
该指针类型为一个CALLBACK的函数,
在相应的回调函数中实现对参数的设置,
Top
回复人:sunman1982(冥王星) ( 三级(初级)) 信誉:100 2005-6-8 17:04:58 得分:0
?
chinunix kunx right?
Top
回复人:laolaoliu2002(老刘) ( 一级(初级)) 信誉:100 2005-6-8 17:37:13 得分:0
?
使用回调函数实际上就是在调用某个函数(通常是 API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。至于如何定义回调函数,跟具体使用的API函数有关,一般在帮助中有说明回调函数的参数和返回值等。C++中一般要求在回调函数前加CALLBACK,这主要是说明该函数的调用方式。DialogBox的回调函数实际上是个窗口过程,用来处理所有消息。其定义为:
BOOL CALLBACK DialogProc(
HWND hwndDlg, // handle of dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
在Win32 API中有详细说明。一般使用C++ Builder或MFC的往往没有使用SDK编程的经验,建议找一些SDK编程的书看一下,否则很难理解如何使用窗口过程。
至于钩子函数,只是回调函数的一个特例。习惯上把与SetWindowsHookEx函数一起使用的回调函数称为钩子函数。也有人把利用VirtualQueryEx安装的函数称为钩子函数,不过这种叫法不太流行。
=====================================================================
均为复制,并非原创,但能讲清楚问题
发表评论
-
c#中 父类调用子类的属性、方法
2016-08-17 17:50 4450我们习惯认为,子类对父类是不可见的,或者说父类不知道 ... -
在IIS 7.5中部署Web项目
2013-08-16 15:49 738http://www.soaspx.com/dotnet/se ... -
c# 拖动控件闪烁
2012-11-06 14:41 1353最近几天在做画线框的工作,类似于截屏之后修改截屏大小的那种, ... -
UDP用同一端口收发数据 c#
2012-10-17 13:02 4725之前用UdpClient,发现当开了一个端口用于监听接收 ... -
Windows 7下VS2008升级补丁
2012-06-04 11:29 5在Windows 7下,VS2008试用版无法正常升级到正式版 ... -
C#读取exe版本号
2012-04-20 10:44 1219//通常我们做软件自动更新,需要比较新文件与旧文件的版本 ... -
c#读取php序列化字符串
2011-06-04 16:25 1172详见附件 -
c#获取网页代码
2011-03-22 16:58 1121using System; using System. ... -
.NET连接mysql数据库 MySQLDriverCS.dll
2011-03-22 16:30 1682string mysqlConn = new MySQ ... -
一些容易出错的地方(持续更新)
2010-04-16 12:39 7651.在html 或者aspx文件里去掉这段代码<!DOC ... -
转 :C# 序列化与反序列化
2010-04-01 13:13 11841序列化:是将对象的状态存储到特定的存储介质中的过程,在序列化 ... -
泛型类(普通类)中的普通方法和泛型方法
2009-10-31 16:48 946在普通类中用泛型方法 public class A { ... -
c#泛型(包括泛型抽象类的继承)
2009-10-17 19:26 35941.泛型和泛型强制转换 using System; ... -
.net提供的5种request-response方法一
2009-09-06 17:16 1780.net提供了三种基本方法和两种底层方法来发送ht ... -
C#三种模拟自动登录和提交POST信息的实现方法
2009-06-09 10:57 3223C#三种模拟自动登录和提交POST信息的实现方法 ... -
.Net下WinForm换肤控件整理
2009-06-08 09:13 22991. 东日IrisSkin IrisSkin 共有两个版本,一 ... -
论反射
2009-05-27 10:20 8391 反射 反射是很多类库在实现一些很炫的功能的时候会常用 ... -
C#装箱与拆箱
2009-04-30 14:54 1005要掌握装箱与拆箱,就必须了解CTS及它的特点。 NET重要技 ... -
遍历页面上的下拉框元素,设置初始值的4种写法
2009-04-30 14:51 1248foreach (Control co ... -
c# 特性/属性(Attribute) 以及使用反射查看自定义特性
2009-04-20 16:10 4750可能很多人还不了解特性,所以我们先了解一下 ...
相关推荐
C#引入了委托(Delegate)的概念,而C++则依赖于回调函数(Callback Function)来实现类似的功能。这两者都是为了实现异步操作或者在不同组件之间传递控制权。本文将深入探讨C#中的委托以及C++中的回调函数,并阐述...
在C#中,我们可以定义一个委托类型,它相当于一个函数指针。这个委托将代表我们要在C++中调用的函数。例如: ```csharp public delegate void MyCallback(string message); ``` 然后,我们创建一个类并实现这个...
总结来说,C#调用C++动态库并处理回调函数的关键在于正确地定义C++的函数接口,创建匹配的C#委托类型,使用P/Invoke进行调用,并注册合适的回调方法。这种技术在需要高性能计算、利用现有C++库或者与其他系统交互时...
C++的回调函数需要考虑函数指针的调用约定,通常使用`__stdcall`约定,以确保调用者清理堆栈。 在C#中定义回调函数的委托类型: ```csharp [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void ...
为了调用C++ DLL中的回调函数,C#需要创建一个委托类型,这个委托类型对应于C++回调函数的原型。然后,C#可以实例化这个委托,并将其传递给DLL。当DLL在适当的时候调用这个回调函数时,实际上是在调用C#中对应的委托...
C++使用函数指针,而C#使用委托,两者需要在互操作层面上进行转换。 1. **C++ DLL的创建:** 在C++中,我们需要定义一个回调函数的原型,然后声明一个函数接口,该接口将接受这个回调函数作为参数。C++ DLL中的回...
总结,C#调用C++动态库并实现C++回调C#函数的关键在于理解P/Invoke的工作原理、C++的导出函数定义以及C#中委托和函数指针的使用。在实际应用中,还需要注意内存管理和异常处理,确保跨语言交互的稳定性和安全性。...
在C++中,回调函数通常通过函数指针或函数对象来实现,而在C#中,我们可以使用委托来达到类似的效果。本文将探讨如何在C#中使用委托实现C++的回调函数,并结合VS2015和VS2019环境,讨论如何处理UDP快速通信中的数据...
委托的作用类似于C/C++中的函数指针,但它比函数指针更安全,更易于使用。委托被广泛用于事件处理和回调函数中。 事件(Event)在C#中是一种特殊的委托,它是类或对象发布消息或通知的方式,用于通知其他对象某个...
这里,`CallingConvention`可以设置为`StdCall`或`Cdecl`,具体取决于C++函数的调用约定。 2. **声明函数原型**:接下来,定义一个C#方法来表示C++函数。由于C++函数可能包含指针作为参数,因此我们需要正确地映射...
2. **C#中的委托类型**:在C#中,我们需要创建一个与C++回调函数匹配的委托类型。 ```csharp public delegate void CallbackDelegate(string str, int[] arr); ``` 3. **P/Invoke**:使用C#的`DllImport`特性来导入...
委托是类型安全的函数指针,它可以引用一个或多个具有相同签名的方法。 1. **创建委托类型:** 在C#中,我们需要定义一个委托类型,该类型描述了回调函数的签名。这通常包括返回类型和参数列表。例如,如果我们的...
它可以将方法作为参数传递,类似于C++中的函数指针,但是委托是类型安全和可靠的。 在上面的代码中,我们定义了一个委托类型`ProcessInfoDelegate`,它的签名为`string ProcessInfoDelegate(string rawMessage)`,即...
- 创建一个C#委托类型,对应C++的回调函数类型: ```csharp public delegate void UnityCallback(int data); ``` - 实现Unity中的回调函数: ```csharp void UnityCallbackHandler(int data) { // 处理回调...
在C++ DLL中,你需要定义一个与`CallbackDelegate`签名相匹配的函数指针类型,并创建一个全局变量或静态成员来存储回调函数。 回调函数是跨语言和跨进程通信中的关键组件,正确理解和使用回调能够帮助我们构建灵活...
c# Csharp调用 c++库 参数为导入和导出指针两种 包含C++ DLL源码 如fun(cont char* A,char*B) A为输入参数,B为输出参数-C# CSharp call C++ DLL lib dll function param use export and import eg: fun(cont char*...
C++ 与C#之间的指针参数传递,实现无限量数据的传递,轻松无压力,方便在C++里面获取或者从C#传递数据到C++的动态库调用内。
在C++中,回调函数通常是通过函数指针实现的。当一个函数A需要在某个操作完成后调用用户定义的函数B时,A会接受一个函数指针作为参数,这个指针指向函数B。这样,当条件满足时,A可以通过这个指针调用B。 在DLL中...