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

    技术2026-01-06  4

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

    3.1  回调函数概念介绍

    3.2  怎样在C中实现回调函数

    3.3  实例解析qsort的用法

    3.4  怎样实现静态C++成员函数的回调

    3.5  怎样实现非静态C++成员函数的回调

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

     

    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的第一个elementnElementsfielditems的数目,sizeOfAnElement是一个item的字节数。cmpFunccomparison-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(注:如果通过全局变量,则必须保证它总能指向正确的对象)。当然,你还需要传递成员函数的参数。Wrappervoid指针转换为相应类实例的指针并调用成员函数。下面有两个例子:

     

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

    }

     

     

    最新回复(0)