设置回调函数,该函数是类的非静态成员函数

2023-11-23

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范围。

如果您遇到需要一个不带用户上下文参数(avoid*该函数只是传递给回调)你有问题。

如果您确实有用户上下文,那就很容易了。传递对象指针作为上下文,并使用包装函数作为实际的回调:

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 中禁用执行保护),它是特定于 CPU 的(因为你需要生成正确的代码)对于每个),并且存在管理存根内存的问题。另一方面,有时这是唯一有效的方法。 Delphi 有时为其窗口和挂钩过程做这种事情,ATL 也这样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设置回调函数,该函数是类的非静态成员函数 的相关文章

随机推荐