0

ここの一番上の回答のリンクされたコードに基づいてイベントマネージャーを実装しようとしています: Game Objects Talking To Each Other

ただし、コールバックを登録しようとするとエラーが発生します。typedef に関係していることは確かです。正確にどのように機能するかはわかりませんが、リンクされたコードではまったく同じ形式になっています。B クラスはインターフェイスから継承する必要があるのに、なぜ型が異なるのでしょうか。コードを以下の最小の例に要約しました。

#include <iostream>

class Interface;
typedef void (Interface::*Callback)(void *data);

class Interface
{
    public:
        void Register    (Callback func);

};

void Interface::Register(Callback func)
{
    std::cout << "Register" << std::endl;
}


class B : public Interface
{
    public:
        B();
        void Echo(void *data);
};

B::B()
{
    Register( (Callback)Echo );
}

void B::Echo(void *data)
{
    std::cout << "Echo" << std::endl;
}


int main()
{
    B b;
    return 0;
}

g++ 4.6.1 で発生するエラーは次のとおりです。

test.cpp: In constructor ‘B::B()’:
test.cpp:31:22: error: argument of type ‘void (B::)(void*)’ does not match ‘Callback {aka void (Interface::*)(void*)}’

誰かが私が間違っていることを説明してもらえますか? ありがとう

4

2 に答える 2

1

@Kerrek正しく指摘したように、Echoは のメンバーではないため、 としては資格がInterfaceありB::EchoませんInterface::*Callback。ただし、テンプレートを使用してそれを実現できます。たとえば、次のようになります。

template <class T> class Interface {
public:
    typedef void (T::*Callback)(void *data);
    void Register(Callback func) {
        std::cout << "Register" << std::endl;
    }
    // ...
};

class B : public Interface<B> {
public:
    B() {
        Register(&B::Echo);
    }
    void Echo(void *data) {
        // Do something
    }
};
于 2011-12-13T22:28:19.060 に答える
0

std :: function(c ++ 11)またはboost :: function(c ++ 03 + boost)を使用した方が良いと思います

#include <iostream>

class Interface;
typedef void (Interface::*Callback)(void *data);

class Interface
{
    public:
        std::function<void(void*)> register;

            Interface(std::function<void(void*)> register_)
            :    register(register_)   //intializer list
            {}
            virtual ~Interface(){} //put me in
};

void Interface::Register(Callback func)
{
    std::cout << "Register" << std::endl;
}


class B : public Interface
{
    public:
        B();
        void Echo(void *data);
};

B::B()
:   Interface( std::bind(B::Echo, this) )
{}

void B::Echo(void *data)
{
    std::cout << "Echo" << std::endl;
}

純粋な仮想を使用していない理由は私を超えていますが

class Interface
{
    public:
        virtual void Echo(void*)=0;

};

void B::Echo(void *data) //implements Echo
{
    std::cout << "Echo" << std::endl;
}

インターフェイスを呼び出す->echoは子を呼び出します

パフォーマンスが必要な場合は、

http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

また、void *には十分注意してください。これらは、一般的に悪いと見なされます。

コメントのアドレスポイントの編集:非純粋な仮想

class Interface
{
public:
    virtual ~Interface(){} //put me in
    virtual void echo(void*){}  //if implementation is not extended it will do nothing.
    //others 
};

これはJavaではなく、インターフェイスは言語によって定義されたものではありません。このようにして、選択できるインターフェースを使用して、実装する部分を選択できます。コールバックがクラスに関係しない場合は、実装しないでください。

void *は、さまざまな理由で悪いものです。C++FAQから

void *を回避します(本当に必要な場合は低レベルの関数とデータ構造内に保持し、タイプセーフなインターフェイス(通常はテンプレート)をユーザーに提示します)

http://www2.research.att.com/~bs/bs_faq.html

「void*」で検索

しかし、基本的にvoid *は、C++が追加する方法から外れたすべての型安全性をバイパスします。ポリモーフィズムやジェネリックコードがないという事実を補うのはCのハックです。

于 2011-12-13T22:18:28.480 に答える