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