如何在不相关的类之间传递C++回调?

fdu*_*uff 5 c++ function-pointers visual-studio-2010

在非升级项目中,我有一个类,它使用基于某个用户操作的计时器(按下/释放按钮).我希望这个类是通用的,因此需要对用户定义的操作进行回调.

// TimerClass.h
typedef void (*timerCallback)(void);
...
Class TimerClass : public CButton {
public:
    void setCallbackShortTime(timerCallback clickFn) { shortCallback = clickFn;} ;
    void setCallbackLongTime(timerCallback clickFn) { longCallback = clickFn;} ;
private:
    timerCallback shortCallback, longCallback;
}


// CMyDlg.h
class CMyDlg : public CDialog
{
public:
    void openLiveViewWindow();
    void openAdminPanelWindow();
    TimerClass _buttonSettings;
}

// CMyDlg.cpp
...
_buttonSettings.setCallbackShortTime(&openLiveViewWindow);
...
Run Code Online (Sandbox Code Playgroud)

现在,从另一个类(DialogClass)我可以使用TimerClass,但我无法将函数指针传递给回调函数.这些功能不是静态的.编译器最终抱怨:

error C2276: '&' : illegal operation on bound member function expression
Run Code Online (Sandbox Code Playgroud)

对此的一些研究指出std::function()并且std::bind()我对这些并不熟悉,并且会对如何解决这个问题提出一些指示.

决议:对于任何有兴趣的人,这里是最终解决方案的砖块

// TimedButton.h
#include <functional>
// define timer callback prototype
typedef std::function<void()> timerCallback;
...
class TimedButton : public CButton
{
public:
    TimedButton();
    ...
    void setCallbackShortTime(timerCallback clickFn) { _shortCallback = clickFn;} ;
    void setCallbackLongTime(timerCallback clickFn) { _longCallback = clickFn;} ;
private:
    timerCallback _shortCallback;
    timerCallback _longCallback;
}

// TimedButton.cpp
...
(_longCallback)();  // call long duration fn
...
(_shortCallback)();     // call short duration fn

// in MyDlg.cpp
#include <functional>
...
_buttonSettings.setCallbackShortTime(std::bind(&CMyDlg::openLiveViewWindow, this));
_buttonSettings.setCallbackLongTime(std::bind(&CMyDlg::openAdminPanelWindow, this));
Run Code Online (Sandbox Code Playgroud)

Mik*_*our 2

std::function是一个多态函数对象,它可以用特定的签名包装任何类型的可调用对象。在您的情况下,您希望它不带参数也不返回任何值,因此您可以定义:

typedef std::function<void()> timerCallback;
Run Code Online (Sandbox Code Playgroud)

std::bind允许您通过将参数绑定到参数来使可调用对象适应不同的签名之一。在您的情况下,您希望通过将成员函数绑定到特定对象来调用它来调整成员函数:

_buttonSettings.setCallbackShortTime(std::bind(&CMyDlg::openLiveViewWindow, this));
Run Code Online (Sandbox Code Playgroud)

请注意,这些是在 2011 年引入的,因此较旧的编译器不支持它们。在这种情况下,您可以使用非常相似的 Boost 或 TR1 库,或者创建您自己的可调用类,其中包含指向成员函数的指针和指向要调用它的对象的指针/引用。