天天看点

3 怎样在C和C++中实现回调函数

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*))

{

         Int bigger = cmpFunc(item1, item2);  //make callback

}

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, 100, sizeof(field[0]),

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);

};

//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))

{

         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);

};

//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))

{

         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);

}