实现类成员函数作为回调函数

3星 · 超过75%的资源 需积分: 10 27 下载量 8 浏览量 更新于2024-09-18 收藏 40KB DOC 举报
"本文将探讨如何使类的成员函数作为回调函数,以及为什么通常成员函数不能直接作为回调函数,并提供解决方法。回调函数是编程中常见的机制,它允许将一个函数作为参数传递给另一个函数,然后在特定时刻由该函数执行。在Windows环境下,回调函数通常使用CALLBACK修饰符来指定_stdcall调用约定。stdcall约定要求被调用者清理堆栈,即函数在执行完毕后负责弹出其参数。" 在C++中,类的成员函数通常不能直接作为回调函数,原因在于成员函数与非成员函数在内存布局和调用约定上存在差异。成员函数有一个隐含的`this`指针,它指向调用该成员函数的对象。这意味着成员函数需要额外的上下文信息,即所属对象的地址,而普通回调函数通常不期望这样的行为。此外,成员函数的调用约定可能与全局函数不同,这可能导致在跨函数调用时出现问题。 为了解决这个问题,我们可以采用以下几种策略: 1. 使用静态成员函数:静态成员函数没有`this`指针,它们可以像全局函数一样被调用。然而,静态成员函数无法访问类的非静态成员,因此这种方法只适用于不需要访问类状态的场景。 2. 使用函数指针和std::bind:C++11引入了`std::bind`,它允许我们将成员函数绑定到特定的对象实例,创建一个新的可调用对象。例如: ```cpp class MyClass { public: void myMemberFunc(int arg); }; MyClass obj; auto boundFunc = std::bind(&MyClass::myMemberFunc, &obj, std::placeholders::_1); someCallbackFunction(boundFunc); ``` 这里,`std::placeholders::_1`表示保留第一个参数位置,用于传递给`myMemberFunc`。 3. 使用lambda表达式:C++11也引入了lambda表达式,它们可以捕获上下文(包括对象实例)并创建一个可调用对象。例如: ```cpp class MyClass { public: void myMemberFunc(int arg); }; MyClass obj; someCallbackFunction([&obj](int arg) { obj.myMemberFunc(arg); }); ``` 在这个例子中,lambda表达式捕获了`obj`的引用,使得`myMemberFunc`能在回调时访问`obj`。 4. 使用std::function和std::mem_fn:`std::function`可以存储任何可调用对象,包括成员函数。`std::mem_fn`是一个工具函数,可以将成员函数转换为可调用对象。例如: ```cpp class MyClass { public: void myMemberFunc(int arg); }; MyClass obj; std::function<void(int)> callback = std::bind(std::mem_fn(&MyClass::myMemberFunc), &obj, std::placeholders::_1); someCallbackFunction(callback); ``` 每种方法都有其适用的场景和优缺点。理解这些策略及其工作原理对于在C++中灵活地使用类的成员函数作为回调函数至关重要。在选择合适的方法时,应考虑性能、代码可读性以及对C++标准库的依赖程度。
2018-08-03 上传
如qsort 等函数需要函数指针才能回调 用此函数库可以将成员函数指针转为普通函数指针 测试代码如下 #include <stdio.h> #include <algorithm> #include <vector> #include <string> #include <iostream> #include <math.h> using cmpfunc = int(__cdecl*)(const void*, const void*); using DebugArrayFunc = void(__stdcall *)(std::string &out;); #include "thunk.h" class MySort { public: int Rule; MySort(int a):Rule(a){} // 回调函数 template<typename T> int __cdecl sort(const void* a, const void* b); }; class Test { public: std::vector<int> mm; void Sort(int (*comp)(const void *,const void *)) { return qsort(mm._Myfirst,mm.size(),sizeof(int),comp); } void Entry(DebugArrayFunc func) { std::string string; cmpfunc comp; TemplateThunk athunk; // 正序 comp = (cmpfunc)athunk.GetCall(&MySort;::sort<int>, &MySort;(0)); Sort(comp); func(string); std::cout << string << std::endl; // 逆序 comp = (cmpfunc)athunk.GetCall(&MySort;::sort<int>, &MySort;(1)); Sort(comp); func(string); std::cout << string << std::endl; } }; class CallBack { public: std::vector<int> *pthis; CallBack(std::vector<int> *ff):pthis(ff){} void __stdcall DebugArray(std::string &out;) { char buff[100]; char *aa = buff; for each (auto a in *pthis) { aa += sprintf(aa, "%d ", a); } out.assign(buff); } }; void main() { TemplateThunk athunk; Test tt; tt.mm = { 1, 3, 7, 8, 5, 6, 4, 2, 3, 10 }; tt.Entry(athunk.GetCall(&CallBack;::DebugArray,&CallBack;(&tt;.mm))); } template <typename T> int __cdecl MySort::sort(const void* a, const void* b) { return Rule ? *static_cast<const T*>(a)-*static_cast<const T*>(b) : *static_cast<const T*>(b)-*static_cast<const T*>(a); }