posts - 16, comments - 0, trackbacks - 0, articles - 0

回调函数

Posted on 2008-12-05 11:04 dengbo 阅读(265) 评论(0)  编辑 收藏 引用
 

函数

20070527 星期日 16:07



  于很多初学者来,往往得回函数很神秘,很想知道回函数的工作原理。本文将要解是回函数、它有什要使用它等等问题,在始之前,假你已熟知了函数指

  什是回函数?

  而言之,回函数就是一个通函数指针调用的函数。如果你把函数的指(地址)作参数传递给另一个函数,当个指被用为调用它所指向的函数,我说这是回函数。

  要使用回函数?

  因可以把用者与被用者分用者不是被用者,所有它需知道的,只是存在一个具有某特定原型、某些限制条件(如返回值为int)的被用函数。

  如果想知道回函数在实际中有什作用,先假这样情况,我写一个,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排序、shake排序等等,但使更加通用,不想在函数中嵌入排序逻辑,而使用者来实现逻辑;或者,想让库可用于多数据型(intfloatstring),此么办呢?可以使用函数指,并行回

  回可用于通知机制,例如,有要在程序中置一个计时器,到一定时间,程序会得到相的通知,但通知机制的实现的程序一无所知。而此,就需有一个特定原型的函数指,用个指行回,来通知我的程序事件已经发生。实际上,SetTimer() API使用了一个回函数来通知计时器,而且,万一没有提供回函数,它会把一个消息往程序的消息列。

  另一个使用回机制的API函数是EnumWindow(),它枚屏幕上所有的顶层窗口,为每个窗口用一个程序提供的函数,并传递窗口的理程序。如果被用者返回一个,就继续进行迭代,否,退出。EnumWindow()并不心被用者在何,也不心被用者用它传递理程序做了什,它只心返回,因基于返回,它将继续执行或退出。

  不管怎么说,回函数是继续C言的,因而,在C++中,只在与C建立接口,或与已有的回接口打交道,才使用回函数。除了上述情况,在C++使用虚方法或函数符(functor),而不是回函数。

  一个简单的回函数实现

  下面建了一个sort.dll动态链,它出了一个名CompareFunction--typedef int (__stdcall *CompareFunction)(const byte*, const byte*),它就是回函数的型。另外,它也出了两个方法:Bubblesort()Quicksort()两个方法原型相同,但实现了不同的排序算法。

void DLLDIR __stdcall Bubblesort(byte* array,int size,int elem_size,CompareFunction cmpFunc);

void DLLDIR __stdcall Quicksort(byte* array,int size,int elem_size,CompareFunction cmpFunc);


  两个函数接受以下参数:

  ·byte * array:指向元素数的指(任意型)。

  ·int size:数中元素的个数。

  ·int elem_size:数中一个元素的大小,以字节为单位。

  ·CompareFunction cmpFunc有上述原型的指向回函数的指

  两个函数的会组进行某排序,但次都需决定两个元素哪个排在前面,而函数中有一个回函数,其地址是作一个参数传递进来的。对编写者来,不必介意函数在何处实现,或它怎实现的,所需在意的只是两个用于比的元素的地址,并返回以下的某个写者和使用者都必遵守定):

  ·-1:如果第一个元素小,那它在已排序好的数中,应该排在第二个元素前面。

  ·0:如果两个元素相等,那的相位置并不重要,在已排序好的数中,在前面都无所

  ·1:如果第一个元素大,那在已排序好的数中,它应该排第二个元素后面。

  基于以上定,函数Bubblesort()实现如下,Quicksort()就稍微复杂一点:

void DLLDIR __stdcall Bubblesort(byte* array,int size,int elem_size,CompareFunction cmpFunc)
{
 for(int i=0; i < size; i++)
 {
  for(int j=0; j < size-1; j++)
  {
   //函数
   if(1 == (*cmpFunc)(array+j*elem_size,array+(j+1)*elem_size))
   {
    //两个相比的元素相交
    byte* temp = new byte[elem_size];
    memcpy(temp, array+j*elem_size, elem_size);
    memcpy(array+j*elem_size,array+(j+1)*elem_size,elem_size);
    memcpy(array+(j+1)*elem_size, temp, elem_size);
    delete [] temp;
   }
  }
 }
}


  注意:因为实现中使用了memcpy(),所以函数在使用的数据型方面,会有所局限。

  使用者来,必有一个回函数,其地址要传递给Bubblesort()函数。下面有二个简单的示例,一个比两个整数,而另一个比两个字符串:

int __stdcall CompareInts(const byte* velem1, const byte* velem2)
{
 int elem1 = *(int*)velem1;
 int elem2 = *(int*)velem2;

 if(elem1 < elem2)
  return -1;
 if(elem1 > elem2)
  return 1;

 return 0;
}

int __stdcall CompareStrings(const byte* velem1, const byte* velem2)
{
 const char* elem1 = (char*)velem1;
 const char* elem2 = (char*)velem2;
 return strcmp(elem1, elem2);
}


  下面另有一个程序,用于测试以上所有的代,它传递了一个有5个元素的数组给Bubblesort()Quicksort(),同时还传递了一个指向回函数的指

int main(int argc, char* argv[])
{
 int i;
 int array[] = {5432, 4321, 3210, 2109, 1098};

 cout << "Before sorting ints with Bubblesort\n";
 for(i=0; i < 5; i++)
  cout << array[i] << '\n';

 Bubblesort((byte*)array, 5, sizeof(array[0]), &CompareInts);

 cout << "After the sorting\n";
 for(i=0; i < 5; i++)
  cout << array[i] << '\n';

 const char str[5][10] = {"estella","danielle","crissy","bo","angie"};

 cout << "Before sorting strings with Quicksort\n";
 for(i=0; i < 5; i++)
  cout << str[i] << '\n';

 Quicksort((byte*)str, 5, 10, &CompareStrings);

 cout << "After the sorting\n";
 for(i=0; i < 5; i++)
  cout << str[i] << '\n';

 return 0;
}


  如果想行降序排序(大元素在先),就只需修改回函数的代,或使用另一个回函数,这样编程起来灵活性就比大了。



  上面的代中,可在函数原型中找到__stdcall,因它以双下划线,所以它是一个特定于编译器的展,到底也就是微实现。任何支持开发基于Win32的程序都必支持展或其等价物。以__stdcall标识的函数使用了定,定呢,因所有的Win32 API(除了个接受可参数的除外)都使用它。定的函数在它返回到用者之前,都会从堆中移除掉参数,也是Pascal定。但在C/C++中,定是用者负责清理堆,而不是被用函数;为强制函数使用C/C++定,可使用__cdecl。另外,可参数函数也使用C/C++定。

  Windows操作系采用了定(Pascal定),因其可减小代的体早期的Windows非常重要,因它运行在只有640KB内存的电脑上。

  如果你不喜__stdcall可以使用CALLBACK宏,它定windef.h中:

#define CALLBACK __stdcallor

#define CALLBACK PASCAL //
PASCAL在此被#defined__stdcall


  作函数的C++方法

  因很可能会使用到C++写代,也会想到把回函数写成中的一个方法,但先来看看以下的代

class CCallbackTester
{
 public:
 int CALLBACK CompareInts(const byte* velem1, const byte* velem2);
};

Bubblesort((byte*)array, 5, sizeof(array[0]),
&CCallbackTester::CompareInts);


  如果使用微编译器,将会得到下面编译错误

error C2664: 'Bubblesort' : cannot convert parameter 4 from 'int (__stdcall CCallbackTester::*)(const unsigned char *,const unsigned char *)' to 'int (__stdcall *)(const unsigned char *,const unsigned char *)' There is no context in which this conversion is possible


  是因非静函数有一个外的参数:this将迫使你在成函数前面加上static。当然,有几方法可以解决问题,但限于篇幅,就不再述了

 


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理