设置一个回调函数,该函数是类的非静态成员函数
Setting a callback function which is non static member function of a class
typedef void (*CALLBACK)();
class Filter
{
public:
void callback()
{
cout << "callback" << endl;
}
};
void SetCallback(CALLBACK pCallBack )
{
pCallBack();
}
int main()
{
Filter f;
SetCallback(f.callback);
}
在main中,SetCallback(f.callback); 语句给出错误。谁能帮我解决问题
问题是成员函数不是没有参数的普通函数,因为它始终具有隐式this
参数。
如果您遇到一个传统的 C 接口,该接口需要一个没有用户上下文参数的普通回调函数(函数只是传递给回调的void*
),那么您就有问题了。
如果您确实有用户上下文,则很容易。将对象指针作为上下文传递,并使用包装函数作为实际回调:
typedef void (*CALLBACK)(void*);
class Filter
{
public:
static void CallbackWrapper(void* context) {
static_cast<Filter*>(context)->callback();
}
private:
void callback();
};
int main() {
Filter f;
SetCallback(&Filter::CallbackWrapper, &f);
}
如果您没有上下文,以下是一些选项:
- 将对象存储在全局变量中,并从包装器访问它。这有一个明显的缺点,即使用全局变量,并且不允许以这种方式进行多个回调。对于长时间运行的回调,这真的很糟糕。
- 对上述内容的一个小改进是使用线程局部全局变量。这对于严格范围的回调很有趣,例如,您调用一个函数,该函数将立即多次使用您的回调,然后返回。想
qsort()
.至少这样,您不会遇到线程安全问题。仍然不是长时间运行的回调的选项。
最后,在 - 大多数平台上都可以使用但工作量很大的选项,您可以在运行时生成一个嵌入对象指针的存根函数。这基本上意味着分配一块内存,如果平台使用它,则禁用该内存上的执行保护,并将机器代码放在那里加载对象指针并在其上调用函数。
最后一个选项仍然有很多缺点:它非常特定于平台,甚至可能在某些平台上根本不起作用(您无法在 iOS、AFAIK 中禁用执行保护),它是特定于 CPU 的(因为您需要为每个生成正确的代码),并且存在管理存根内存的问题。另一方面,有时它是唯一有效的方法。德尔福有时会为其窗口和钩子程序做这种事情,ATL 也会这样做。
这是我用来实现指向成员函数的指针的回调的方法。
它可能需要C++11。
#include <iostream>
#include <string>
#include <functional>
using namespace std;
struct MessageSource
{
function<void(const string& msg)> _callback;
template<typename A, typename B>
void connect(A func_ptr, B obj_ptr)
{
_callback = bind(func_ptr, obj_ptr, placeholders::_1);
}
void send_msg(const string& msg)
{
if (_callback)
_callback(msg);
}
void disconnect()
{
_callback = nullptr;
}
};
struct Printer
{
void print(const string& msg) { std::cout << msg << std::endl; };
};
int main()
{
{
Printer p;
MessageSource s;
s.connect(&Printer::print, &p);
s.send_msg("test");
s.disconnect();
s.send_msg("test again");
}
system("pause");
return 0;
}
关于"非静态方法"回调的更简单示例:
#include <iostream>
#include <string>
#include <functional>
using namespace std::placeholders;
class Test
{
public:
void SetValue(int i) { v = i;}
int v;
};
int main()
{
Test a { 123 };
std::cout << a.v << std::endl; // print 123
auto _callback = std::bind(&Test::SetValue, &a, _1); // create the callback
_callback(55); // call the callback
std::cout << a.v << std::endl; // print 55
return 0;
}
输出:
123
55
您应该考虑回调到底是什么以及如何调用成员函数。
当你给出一个回调函数时,你只给出一个函数的地址,该函数稍后将使用你通常几乎无法控制的参数调用。
调用成员函数时,其第一个参数是this
指针,即对调用该方法的对象的引用。
这就是为什么不能使用成员方法作为回调的原因。您只能使用不需要特殊参数(对程序员隐含,但在编译器的角度来看是真实的)参数this
的 true 函数或静态成员函数。
相关文章:
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 如何在C++中使用非静态成员函数作为回调函数
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- 静态成员函数使用相同的名称时出现模板类型名称错误
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 如何在友元函数中使用静态成员而不添加前缀 [类名]::
- C++构造函数和静态成员
- 为什么传递非静态成员函数会导致编译错误?
- 非静态成员失败的线程调用函数
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 非静态成员函数的 decltype 格式不正确吗?
- 为什么 std::sort 找不到合适的(静态成员)函数重载?
- std::异步与非静态成员函数
- C++无效使用非静态成员函数?
- 指向重载静态成员的函数指针 - 在unique_ptr中用作自定义删除器
- 未使用的C++未优化的静态成员函数/变量
- C++:如何返回指向非静态成员函数的指针?
- 有没有一种方法可以使全局函数/静态成员函数一次可呼出
- 函数静态成员变量
- 隐藏模板化的辅助函数——静态成员或未命名的命名空间