99

私はこれが何度も尋ねられてきたことを知っています.

私はこれを持っています、それはシンプルで、それは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);
};

EventHandler::addHandler()と の両方MyClassで機能するように、どのように書き換えることができますかYourClass。申し訳ありませんが、それは私の脳の仕組みにすぎません。なぜ/どのように機能するかを理解する前に、何が機能するかの簡単な例を見る必要があります. これを機能させるためのお気に入りの方法がある場合は、今こそそれを披露するときです。そのコードをマークアップして投稿してください。

[編集]

回答されましたが、チェックマークを付ける前に回答が削除されました。私の場合の答えは、テンプレート化された関数でした。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);
        }
};
4

6 に答える 6

191

std::function静的メソッドを使用してクラス インスタンスへのポインターを渡す代わりに、新しい C++11 標準の機能を使用できますstd::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);
        }
};

この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;
}

そうでなければ暗黙的なポインタを引数としてstd::bind明示的に指定する必要があるため、ハンドラを追加するときに使用する必要があります。this独立した関数がある場合は、使用する必要はありませんstd::bind:

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

int main()
{
    // ...
    handler->addHandler(freeStandingCallback);
}

イベント ハンドラーでstd::functionオブジェクトを使用すると、新しい C++11ラムダ関数も使用できるようになります。

handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; });
于 2013-01-07T03:41:02.350 に答える
4

あなたがしたいことは、このコードを処理するインターフェースを作成し、すべてのクラスがインターフェースを実装することです。

class IEventListener{
public:
   void OnEvent(int x) = 0;  // renamed Callback to OnEvent removed the instance, you can add it back if you want.
};


class MyClass :public IEventListener
{
    ...
    void OnEvent(int x); //typically such a function is NOT static. This wont work if it is static.
};

class YourClass :public IEventListener
{

これが機能するために、「コールバック」関数は非静的であることに注意してください。これは改善だと思います。静的にしたい場合は、JaredC がテンプレートで提案しているように行う必要があります。

于 2013-01-07T03:29:24.037 に答える
1

MyClassどちらも抽象(仮想)メソッドを持つものからYourClass派生できます。タイプandのオブジェクトを受け入れ、オーバーライドして、コールバック動作の特定の実装を提供できます。SomeonesClassCallbackaddHandlerSomeonesClassMyClassYourClassCallback

于 2013-01-07T03:30:44.437 に答える
0

異なるパラメーターを持つコールバックがある場合、次のようにテンプレートを使用できます:
// コンパイル: g++ -std=c++11 myTemplatedCPPcallbacks.cpp -o myTemplatedCPPcallbacksApp

#include <functional>     // c++11

#include <iostream>        // due to: cout


using std::cout;
using std::endl;

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

class OtherClass
{
    public:
        OtherClass();
        static void Callback(OtherClass* instance, std::string str);
    private:
        std::string private_str;
};

class EventHandler
{

    public:
        template<typename T, class T2>
        void addHandler(T* owner, T2 arg2)
        {
            cout << "\nHandler added..." << endl;
            //Let's pretend an event just occured
            owner->Callback(owner, arg2);
         }   

};

MyClass::MyClass()
{
    EventHandler* handler;
    private_x = 4;
    handler->addHandler(this, private_x);
}

OtherClass::OtherClass()
{
    EventHandler* handler;
    private_str = "moh ";
    handler->addHandler(this, private_str );
}

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

void OtherClass::Callback(OtherClass* instance, std::string private_str)
{
    cout << " OtherClass::Callback(OtherClass* instance, std::string private_str) ==> " 
         << " Hello " << instance->private_str << endl;
}

int main(int argc, char** argv)
{
    EventHandler* handler;
    handler = new EventHandler();
    MyClass* myClass = new MyClass();
    OtherClass* myOtherClass = new OtherClass();
}
于 2014-10-09T15:36:57.047 に答える