6

在一个非增强项目中,我有一个类使用基于某个用户操作(按下/释放按钮)的计时器。我想要这个类是通用的,所以它需要回调用户定义的操作。

// 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);
...

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

error C2276: '&' : illegal operation on bound member function expression

对此的一些研究指出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));
4

4 回答 4

3

执行此操作的老式方法是让您的回调函数接受一个附加void*参数,为此您传递一个指向您希望调用该函数的对象的指针。然后,您为回调使用静态成员函数,并让它将指针转换为正确的对象并调用您的真正回调。

typedef void (*timerCallback)(void*);
...
void setCallbackShortTime(timerCallback clickFn, void* object) { shortCallback = clickFn; shortCallbackObject = object;} ;
void setCallbackLongTime(timerCallback clickFn, void* object) { longCallback = clickFn; longCallbackObject = object;} ;
...

static void openLiveViewWindowCallback(void* object) { ((CMyDlg*)object)->openLiveViewWindow(); }
void openLiveViewWindow();
于 2012-08-13T18:54:41.620 回答
2

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

typedef std::function<void()> timerCallback;

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

_buttonSettings.setCallbackShortTime(std::bind(&CMyDlg::openLiveViewWindow, this));

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

于 2012-08-13T18:45:58.337 回答
2

您不能将指针传递给类的方法,只能传递普通函数。我建议深入std::function()研究,因为您使用的是支持它们的 VS2010。有一个很好的(而且很长的)教程来描述它们以及更多here

于 2012-08-13T18:47:59.857 回答
1

您可以创建一个充当函数指针的多态模板类。

class TFunctorBase
{
public:
    TFunctorBase(void) {}
    virtual ~TFunctorBase(void) {}
    virtual void operator()(void) = 0;
};

// derived template class
template <class TClass> class TFunctor : public TFunctorBase
{
private:
    void (TClass::*fpt)();   // pointer to member function
    TClass* pt2Object;                  // pointer to object

public:
    TFunctor(TClass* _pt2Object, void(TClass::*_fpt)())
    { pt2Object = _pt2Object; fpt = _fpt;};

    virtual void operator()(void)
    { (*pt2Object.*fpt)();};              // execute member function
};

初始化仿函数对象:

TFunctor<MyClass> obj(&myInstance, &MyClass::myMemberFunction);

并使用它:

(*obj)(); 
//(*obj)(42); for operator()(int)

这是一个例子:

class ClassA
{
public:
   void function1(int a, string b);
};

ClassA objA;
TFunctor<ClassA> functor(&objA,&ClassA::function);
(*functor)(42, "pumpkin"); //assuming you added virtual void operator()(int, string) to TFunctorBase

这是关于函子的一个很好的资源以及我上面描述的实现。 http://www.newty.de/fpt/functor.html#chapter4

于 2012-08-14T04:17:32.880 回答