`
starnc
  • 浏览: 145137 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

c#委托相当于c++的回调函数(函数指针)

    博客分类:
  • .NET
阅读更多

       回调函数,就是由你自己写的。你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在回调函数里完成你要做的事。 

 

 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#委托与C++回调函数处理

    C#引入了委托(Delegate)的概念,而C++则依赖于回调函数(Callback Function)来实现类似的功能。这两者都是为了实现异步操作或者在不同组件之间传递控制权。本文将深入探讨C#中的委托以及C++中的回调函数,并阐述...

    C#在C++中注册回调函数

    在C#中,我们可以定义一个委托类型,它相当于一个函数指针。这个委托将代表我们要在C++中调用的函数。例如: ```csharp public delegate void MyCallback(string message); ``` 然后,我们创建一个类并实现这个...

    C#调用C++动态库中自身定义的回调函数

    总结来说,C#调用C++动态库并处理回调函数的关键在于正确地定义C++的函数接口,创建匹配的C#委托类型,使用P/Invoke进行调用,并注册合适的回调方法。这种技术在需要高性能计算、利用现有C++库或者与其他系统交互时...

    C#调用C++动态库,执行回调函数并传递结构体参数

    C++的回调函数需要考虑函数指针的调用约定,通常使用`__stdcall`约定,以确保调用者清理堆栈。 在C#中定义回调函数的委托类型: ```csharp [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void ...

    C# Csharp 调用 C++的DLL中的回调函数

    为了调用C++ DLL中的回调函数,C#需要创建一个委托类型,这个委托类型对应于C++回调函数的原型。然后,C#可以实例化这个委托,并将其传递给DLL。当DLL在适当的时候调用这个回调函数时,实际上是在调用C#中对应的委托...

    C#实现C++dll回调函数.rar

    C++使用函数指针,而C#使用委托,两者需要在互操作层面上进行转换。 1. **C++ DLL的创建:** 在C++中,我们需要定义一个回调函数的原型,然后声明一个函数接口,该接口将接受这个回调函数作为参数。C++ DLL中的回...

    C#调C++动态库Dll C++回调C#函数

    总结,C#调用C++动态库并实现C++回调C#函数的关键在于理解P/Invoke的工作原理、C++的导出函数定义以及C#中委托和函数指针的使用。在实际应用中,还需要注意内存管理和异常处理,确保跨语言交互的稳定性和安全性。...

    C#中用委托实现C++的回调函数

    在C++中,回调函数通常通过函数指针或函数对象来实现,而在C#中,我们可以使用委托来达到类似的效果。本文将探讨如何在C#中使用委托实现C++的回调函数,并结合VS2015和VS2019环境,讨论如何处理UDP快速通信中的数据...

    19.C#中委托、事件和回调函数的理解.pdf

    委托的作用类似于C/C++中的函数指针,但它比函数指针更安全,更易于使用。委托被广泛用于事件处理和回调函数中。 事件(Event)在C#中是一种特殊的委托,它是类或对象发布消息或通知的方式,用于通知其他对象某个...

    C# 调用C++DLL(函数参数包含指针)

    这里,`CallingConvention`可以设置为`StdCall`或`Cdecl`,具体取决于C++函数的调用约定。 2. **声明函数原型**:接下来,定义一个C#方法来表示C++函数。由于C++函数可能包含指针作为参数,因此我们需要正确地映射...

    C#调用C++的dll实例,回调函数,string和int数组参数传递

    2. **C#中的委托类型**:在C#中,我们需要创建一个与C++回调函数匹配的委托类型。 ```csharp public delegate void CallbackDelegate(string str, int[] arr); ``` 3. **P/Invoke**:使用C#的`DllImport`特性来导入...

    C#传递回调函数

    委托是类型安全的函数指针,它可以引用一个或多个具有相同签名的方法。 1. **创建委托类型:** 在C#中,我们需要定义一个委托类型,该类型描述了回调函数的签名。这通常包括返回类型和参数列表。例如,如果我们的...

    c#的回调函数(delegate关键字)

    它可以将方法作为参数传递,类似于C++中的函数指针,但是委托是类型安全和可靠的。 在上面的代码中,我们定义了一个委托类型`ProcessInfoDelegate`,它的签名为`string ProcessInfoDelegate(string rawMessage)`,即...

    在Unity3d中使用C++ DLL 之 回调 示例

    - 创建一个C#委托类型,对应C++的回调函数类型: ```csharp public delegate void UnityCallback(int data); ``` - 实现Unity中的回调函数: ```csharp void UnityCallbackHandler(int data) { // 处理回调...

    C# 回调CV++ DLL 三种方法 和 多类之间共享一个回调函数

    在C++ DLL中,你需要定义一个与`CallbackDelegate`签名相匹配的函数指针类型,并创建一个全局变量或静态成员来存储回调函数。 回调函数是跨语言和跨进程通信中的关键组件,正确理解和使用回调能够帮助我们构建灵活...

    C# 调用c++ 库 参数为指针类型导出函数

    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#传递数据到C++的动态库调用内。

    VC++回调函数

    在C++中,回调函数通常是通过函数指针实现的。当一个函数A需要在某个操作完成后调用用户定义的函数B时,A会接受一个函数指针作为参数,这个指针指向函数B。这样,当条件满足时,A可以通过这个指针调用B。 在DLL中...

Global site tag (gtag.js) - Google Analytics