使用类成员的C++回调

Ben*_*tFX 76 c++ function callback member

我知道这已被问了很多次,因此很难深入研究这个问题并找到一个有效的简单例子.

我有这个,它很简单,适用于MyClass......

#include <iostream>
using std::cout;
using std::endl;

class MyClass
{
    public:
        MyClass();
        static void Callback(MyClass* instance, int x);
    private:
        int private_x;
};

class EventHandler
{
    public:
        void addHandler(MyClass* owner)
        {
            cout << "Handler added..." << endl;
            //Let's pretend an event just occured
            owner->Callback(owner,1);
        }
};

EventHandler* handler;

MyClass::MyClass()
{
    private_x = 5;
    handler->addHandler(this);
}

void MyClass::Callback(MyClass* instance, int x)
{
    cout << x + instance->private_x << endl;
}

int main(int argc, char** argv)
{
    handler = new EventHandler();
    MyClass* myClass = new MyClass();
}

class YourClass
{
    public:
        YourClass();
        static void Callback(YourClass* instance, int x);
};
Run Code Online (Sandbox Code Playgroud)

那怎么可以重写,以便EventHandler::addHandler()将与工作都MyClassYourClass.我很抱歉,但这只是我的大脑工作的方式,我需要看一个简单的例子,说明在我理解为什么/如何工作之前有效的方法.如果你有一个最喜欢的方式让这个工作现在是时候展示它,请标记该代码并将其发回.

[编辑]

在回答之前,答案被删除了.在我的案例中,答案是模板化的功能.将addHandler更改为此...

class EventHandler
{
    public:
        template<typename T>
        void addHandler(T* owner)
        {
            cout << "Handler added..." << endl;
            //Let's pretend an event just occured
            owner->Callback(owner,1);
        }
};
Run Code Online (Sandbox Code Playgroud)

Som*_*ude 158

而不是静态方法和身边掠过的指针类的实例,你可以使用新的C++ 11标准功能:std::functionstd::bind:

#include <functional>
class EventHandler
{
    public:
        void addHandler(std::function<void(int)> callback)
        {
            cout << "Handler added..." << endl;
            // Let's pretend an event just occured
            callback(1);
        }
};
Run Code Online (Sandbox Code Playgroud)

addHandler方法现在接受一个std::function参数,这个"函数对象"没有返回值,并以整数作为参数.

要将其绑定到特定函数,请使用std::bind:

class MyClass
{
    public:
        MyClass();

        // Note: No longer marked `static`, and only takes the actual argument
        void Callback(int x);
    private:
        int private_x;
};

MyClass::MyClass()
{
    using namespace std::placeholders; // for `_1`

    private_x = 5;
    handler->addHandler(std::bind(&MyClass::Callback, this, _1));
}

void MyClass::Callback(int x)
{
    // No longer needs an explicit `instance` argument,
    // as `this` is set up properly
    cout << x + private_x << endl;
}
Run Code Online (Sandbox Code Playgroud)

您需要std::bind在添加处理程序时使用,因为您明确需要将其他隐式this指针指定为参数.如果您有独立功能,则不必使用std::bind:

void freeStandingCallback(int x)
{
    // ...
}

int main()
{
    // ...
    handler->addHandler(freeStandingCallback);
}
Run Code Online (Sandbox Code Playgroud)

让事件处理程序使用std::function对象,也可以使用新的C++ 11 lambda函数:

handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; });
Run Code Online (Sandbox Code Playgroud)

  • 谢谢Joachim!这个例子为揭开std :: function和std :: bind的神秘面纱做了很多工作.我肯定会在将来使用它![编辑]我仍然没有得到lambda :) (4认同)
  • 我把它折叠成了我的大项目(大约6,000行.这对我来说很重要.)它使用具有不同回调和参数的按钮定义向量然后将其提供给wxWidgets,因此对象可以在wxFrame中管理自己的按钮.这简化了很多东西!我不能说足够,互联网包含太多的技术和意见,而不是简单的例子. (3认同)
  • “ handler-&gt; addHandler()”,意味着您在某个地方创建了“ EventHandler”对象?好的答案顺便说一句,+ 1。 (2认同)
  • 请注意,您需要占位符的数量与参数的数量相匹配,因此如果回调中有两个参数,您需要使用“...., _1, _2)”等。 (2认同)

rsj*_*ffe 6

这是一个简洁的版本,适用于类方法回调和常规函数回调。在此示例中,为了显示如何处理参数,回调函数采用两个参数:boolint

class Caller {
  template<class T> void addCallback(T* const object, void(T::* const mf)(bool,int))
  {
    using namespace std::placeholders; 
    callbacks_.emplace_back(std::bind(mf, object, _1, _2));
  }
  void addCallback(void(* const fun)(bool,int)) 
  {
    callbacks_.emplace_back(fun);
  }
  void callCallbacks(bool firstval, int secondval) 
  {
    for (const auto& cb : callbacks_)
      cb(firstval, secondval);
  }
private:
  std::vector<std::function<void(bool,int)>> callbacks_;
}

class Callee {
  void MyFunction(bool,int);
}

//then, somewhere in Callee, to add the callback, given a pointer to Caller `ptr`

ptr->addCallback(this, &Callee::MyFunction);

//or to add a call back to a regular function
ptr->addCallback(&MyRegularFunction);
Run Code Online (Sandbox Code Playgroud)

这将特定于 C++11 的代码限制为类 Caller 中的 addCallback 方法和私有数据。至少对我来说,这最大限度地减少了在实施时出错的机会。