【问题标题】:How to implement series of class-member callbacks, that use non-static class fields?如何实现一系列使用非静态类字段的类成员回调?
【发布时间】:2026-01-18 17:00:02
【问题描述】:

我有一系列回调,对输入数据做一些工作,然后调用该系列中的下一个回调。看这个简单的例子(每个回调系列递增并打印值):

#include <stdio.h>
//#include <boost/bind.hpp>
//#include <boost/function.hpp>

//typedef boost::function<void (int i)> DataCallback;
typedef void (*DataCallback)(int i);

class A
{
public:
    DataCallback dataCallback;
    void RegisterCallback(DataCallback callback);
    void Callback(int i);
};

void A::RegisterCallback(DataCallback callback)
{
    dataCallback = callback;
}

void A::Callback(int i)
{    
    dataCallback(++i);
    printf("Callback. i = %i", i);
}

int main (void)
{    
    A a1, a2, a3;

    //a1.RegisterCallback(boost::bind(&A::Callback, &a2));
    //a2.RegisterCallback(boost::bind(&A::Callback, &a3));
    a1.RegisterCallback(a2.Callback);
    a2.RegisterCallback(a3.Callback);

    a3.Callback(1);

    return 0;
}

但是我有一个问题。在 C++ 中,您不能将类成员函数用作回调。据我所知,这个问题的解决方案是将回调函数设为静态。但在这种情况下,我不能使用课堂内字段。为了解决这个问题,我可以提供指向类 (this) 的回调指针并在回调中使用它。但是,就我而言,这意味着我应该向最低回调 (a3.Callback) 提供指向 a2 和 a1 的指针。

在我的实际项目中,我有大约 6 个回调并向第 6 个回调提供指向其他 5 个的指针 - 我认为这是个坏主意。

那么,我的问题是——如何实现这一系列回调?

正如您在代码中看到的,我尝试使用 boost::function 和 boost::bind,但 MSVS2005 在编译时崩溃(优化的编译器已停止工作...)并在 mem_fn.hpp@318 处出现警告 C4180 .这里出了什么问题,这是解决我的问题的最佳方法吗?

【问题讨论】:

  • 听起来像是一个 XY 问题——也许如果你描述你试图解决的实际问题,有一个更好的方法来解决这个问题(几乎每次我看到一般的回滚,我觉得它可能应该是派生自公共基类的类中的虚拟方法)。
  • 在您描述的情况下,只需将您的类实例作为函数参数传递,例如使用void* 或基类指针。然后你可以在回调中强制转换它。

标签: c++ boost callback


【解决方案1】:

是的,我现在使用 Callback() 方法注册 ICallbackable 类,而不是回调。谢谢你的帮助。

#include <stdio.h>

class ICallbackable
{
public:
    virtual void Callback(int i) = 0;
};

class A : public ICallbackable
{
public:
    ICallbackable* dataCallback;
    void RegisterCallback(ICallbackable* callback);
    void Callback(int i);
};

void A::RegisterCallback(ICallbackable* callback)
{
    dataCallback = callback;
}

void A::Callback(int i)
{
    printf("Callback. i = %i\n", i);

    if (dataCallback)
    {
        dataCallback->Callback(++i);
    }    
}

int main (void)
{    
    A a1, a2, a3;

    a1.RegisterCallback(NULL);
    a2.RegisterCallback(&a1);
    a3.RegisterCallback(&a2);

    a3.Callback(1);

    return 0;
}

【讨论】: