3 怎样在C和C++中实现回调函数
3.1 回调函数概念介绍
3.2 怎样在C中实现回调函数
3.3 实例解析qsort的用法
3.4 怎样实现静态C++成员函数的回调
3.5 怎样实现非静态C++成员函数的回调
3怎样在C和C++中实现回调函数 3.1 回调函数概念介绍 函数指针提供了回调函数的概念。我将用大家熟知的排序函数qsort来介绍回调函数的概念。这个函数依照用户的需求对域(field)的 items进行排列。域(field)可以包含任何类型的item。它通过使用void-pointer传给排序函数。同时item的大小以及item的数目也传给排序函数。现在有个问题:这个排序函数怎样在不知道item类型的情况下对域(field)的 items进行排列?答案很简单:排序函数接收一个函数指针,这个函数指针指向comparison-function, comparison-function带两个void-pointer参数(指向两个不同域的items),比较items的序列,并返回结果(以int型返回)。所以每次排序算法需要决定两个items的序列时,只需通过调用comparison-function。 3.2怎样在C中实现回调函数 我用qsort函数来做解释,qsort函数的具体实现请参考Borland Compiler C++5.02(BC5.02) Void qsort(void* field, size_t nElements, size_t sizeOfAnElement, Int(_USERENTRY *cmpFunc)(const void*, const void*)); field 指向被排序的field的第一个element,nElements是field的items的数目,sizeOfAnElement是一个item的字节数。cmpFunc是comparison-function的函数指针。comparison-function带两个void-pointer参数(指向两个不同域的items),比较items的序列,并返回结果(以int型返回)。在函数定义中使用函数指针作为参数显得有点奇怪。使用回调就像使用正常函数调用:只需用函数指针名替换函数名。下面给出示例。注意:所有参数包括函数指针都关联在相关数据上。 Void qsort(…, int(_USEENTRY *cmpFunc)(const void*, const void*)) { /*sort algorithm - note : item1 and item2 are void-pointer*/ Int bigger = cmpFunc(item1, item2); //make callback /*use the result*/ } 3.3实例解析qsort的用法 //----------------------------------------------------------------------- //3.3 How to make a callback in c by the means of the sort function qsort #include <stdlib.h> //due to: qsort #include <time.h> // randomize #include <stdio.h> // printf //comparison-function for the sort-algorithm //two items are taken by void-pointer, converted and compared Int CmpFunc(const void* _a, const void* _b) { Const float* a = (const float*) _a; Const float* b = (const float*) _b; If(*a > *b) return 1;//first item is bigger than the second one->return 1 Else if(*a = *b) return 0; Else return -1; } //example for the use of qsort() Void QSortExample() { Float field[100]; ::randomize(); //initialize random-number-generator For(int c=0; c<100; c++) Field[c] = random(99); //sort using qsort Qsort((void*)field, /*number of items*/ 100, /*size of an item*/ sizeof(field[0]), /*comparison-function*/ CmpFunc); //display first tem elements of the sorted field Printf(“The first ten elements of the sorted field are … /n”); For(int c=0; c<10; c++) Printf(“element #%d contains %.0f/n”, c+1, field[c]); Pirntf(“/n”); } 3.4怎样实现静态C++成员函数的回调 这跟实现C的函数回调一样。静态成员函数不需要一个对象来引用,因此只需跟C函数有相同的签名,相同调用协定、参数、返回值。 3.5怎样实现非静态C++成员函数的回调 非静态C++成员函数指针跟C函数指针不一样,它还需要一个传递一个类实例的this指针。因此非静态成员函数的跟普通函数指针不同,且完全不兼容。如果你想回调一个明确的类的成员函数,只需将普通函数指针改为成员函数指针。但如果你要回调一个任意类的非静态成员函数,怎么办?稍微有点困难。你需写一个静态成员函数作为封装(wrapper)。一个静态成员函数跟C函数有相同格式的签名!然后你将指针转换为 你的类对象你要调用的函数 转换为void* 并将它作为附加参数或通过全局变量传递给wrapper(注:如果通过全局变量,则必须保证它总能指向正确的对象)。当然,你还需要传递成员函数的参数。Wrapper将void指针转换为相应类实例的指针并调用成员函数。下面有两个例子: Example A:类实例指针作为附加参数传递 //3.5Example A: Callback to member function using an additional argument //Task: The function ‘DoItA’ makes something which implies a callback to // the member function ‘Display’. Therefore the wrapper function // ‘Wrapper_To_Call_Display’ is used. #include <iostream.h> //due to: cout Class TClassA { Public: Void Display(const char* text) {cout<<text<<endl;}; Static void Wrapper_To_Call_Display(void* pt2Object, char* text); /*more of TClassA*/ }; //static wrapper function to be able to callback the member function Display() Void TClassA:: Wrapper_To_Call_Display(void* pt2Object, char* string) { //explicitly cast to a pointer to TClassA TClassA* myself = (TClassA*) pt2Object; //call member myself->Display(string); } //function does something which implies a callback //note: of course this function can also be a member function Void DoItA(void* pt2Object, void (*pt2Function)(void* pt2Object, char* text)) { /*do something*/ pt2Function(pt2Object, “hi, I’m calling back using a argument.”);//make callback } //execute example code Void Callback_Using_Argument() { //1. Instantiate object of TClassA TClassA objA; //2.call ‘DoItA’ for<objA> DoItA((void*)& objA, TClassA:: Wrapper_To_Call_Display); } Example B: 类实例指针保存在全局变量里 //--------------------------------------------------------------------------------------------------- //3.5 Example B: Callback to member function using a global variable //Task: The function ‘DoItB’ makes something which implies a callback to // the member function ‘Display’. Therefore the wrapper function // ‘Wrapper_To_Call_Display’ is used. #include <iostream.h> //due to: cout Void* pt2Object; //global variable which pointer to an arbitrary object Class TClassB { Public: Void Display(const char* text) {cout<<text<<endl;}; Static void Wrapper_To_Call_Display(void* pt2Object, char* text); /*more of TClassB*/ }; //static wrapper function to be able to callback the member function Display() Void TClassB:: Wrapper_To_Call_Display(char* string) { //explicitly cast to a pointer to TClassB //warning: <pt2Object> MUST point to an appropriate object! TClassB* myself = (TClassB*) pt2Object; //call member myself->Display(string); } //function does something which implies a callback //note: of course this function can also be a member function Void DoItB(void (*pt2Function)(char* text)) { /*do something*/ pt2Function(“hi, I’m calling back using a argument.”);//make callback } //execute example code Void Callback_Using_Argument() { //1. Instantiate object of TClassB TClassB objB; //2.assign global variable which is used in the static wrapper function //important: never forget to do this!! Pt2Object = (void*)&objB; //3.call ‘DoItB’ for<objB> DoItB(TClassB:: Wrapper_To_Call_Display); }