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引数をパラメータにバインドすることにより、呼び出し可能なオブジェクトを別のシグニチャの1つに適合させることができます。あなたの場合、メンバー関数を特定のオブジェクトにバインドして呼び出すことにより、メンバー関数を適応させたいと考えています。

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

これらは2011年に導入されたため、古いコンパイラはサポートしないことに注意してください。その場合、非常によく似たBoostまたはTR1ライブラリを使用するか、メンバー関数へのポインタと、それを呼び出すオブジェクトへのポインタ/参照を含む独自の呼び出し可能クラスを作成できます。

于 2012-08-13T18:45:58.337 に答える
2

クラスのメソッドへのポインタを渡すことはできず、単純な関数のみを渡すことができます。std::function()それらをサポートするVS2010を使用しているので、を掘り下げることをお勧めします。それらを説明する素晴らしい(そして長い)チュートリアルがここにあります。

于 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 に答える