1. ホーム
  2. c++

[解決済み] クラスメンバを使用したC++コールバック

2023-01-01 22:55:53

質問

これは何度も質問されていることですが、そのため、何がうまくいくかの簡単な例を見つけるのが難しいのです。

私はこれを持っています。これは単純で、次のように動作します。 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() の両方で動作するようにするにはどうしたらよいでしょうか。 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);
        }
};

どのように解決するのですか?

静的メソッドを持ち、クラスインスタンスへのポインタを渡す代わりに、新しい C++11 標準の機能を使用することができます。 std::function 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 の引数を取るようになり、この "function object" は戻り値を持たず、引数として整数を取るようになりました。

特定の関数にバインドするためには 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'; });