1

このコードは、問題を本質的に抽出します。

インフラストラクチャ クラス:

struct EventReceiverBase {
    virtual ~EventReceiverBase() { }
};

template<typename T>
struct EventReceiver : public virtual EventReceiverBase {
    virtual void receiveEvent(T* pSender) = 0;
};

struct EventSender {
    EventReceiverBase* pReceiver;

    template<typename T>
    void sendEvent(T* pSender) {
        EventReceiver<T>* pCastedReceiver =
            dynamic_cast<EventReceiver<T>*>(pReceiver);
        // HERE IS THE PROBLEM
        // pCastedReceiver is null. T is BaseSender. The pointer
        // being casted is really of type EventReceiver<DerivedSender>*,
        // but it tries to cast to EventReceiver<BaseSender>*, and that
        // fails.
        pCastedReceiver->receiveEvent(pSender);
    }
};

ユーザー クラス:

struct BaseSender : public virtual EventSender {
    void f() {
        sendEvent(this);
    }
};
struct DerivedSender : public BaseSender { };

struct MyClass : public virtual EventReceiver<DerivedSender> {
    void receiveEvent(DerivedSender* pSender) { }
};

int main() {
    MyClass my;
    DerivedSender derivedSender;
    derivedSender.pReceiver = &my;
    derivedSender.f();
}

この問題を回避するために、この問題を作り直すことはできますか? イベントの送受信機能を可能な限りこの方法に近づけながら、ユーザー クラスを可能な限りシンプルに保ちたいと考えています。

たとえば、 MyClass を EventReceiver<BaseSender> から派生させることで「修正」することもできますが、イベントを受け取るすべてのクラスで余分な作業が発生するため、これは避けたいと思います。

編集: 実行可能な貼り付け: http://liveworkspace.org/code/4bm6OU $13

4

2 に答える 2

1

問題が発生する理由は、以下の呼び出しfの:内の関数の配置に関係しており、へのポインタを表しています。基本的に、以下の呼び出しBaseSendersendEventthisBaseSender

void f() {
    sendEvent(this);
}

これを書く簡単な方法です:

void f() {
    sendEvent<BaseSender>(this);
}

fこの問題をDerivedSender 修正するために移動します。

別の方法はBaseSender::f、テンプレートを作成することです。

template <typename T>
void f() {
    sendEvent<T>((T*)this);
}

そしてそれをこのように呼びます:

derivedSender.f<DerivedSender>();

これは特に見栄えがよくありませんが、実世界fが大きい状況でのコードのコピー貼り付けの回避策になる可能性があります。

さらに別の解決策はBaseSender、次のようなテンプレートを作成することです。

template<typename T>
struct BaseSender : public virtual EventSender {
    void f() {
        sendEvent((T*)this);
    }
};
struct DerivedSender : public BaseSender<DerivedSender> {
};

これも機能します(ideoneへのリンク)。

于 2012-12-29T12:41:40.257 に答える
0

これは問題になるはずです。本当に奇妙なことをしていない限り、pSender は元のオブジェクトを指します。

ただし、MyClass の receiveEvent はBaseSender *オブジェクトを受け取る必要があり、それを DerivedSender にキャストする必要があります (または、ベースで定義された仮想メソッドのみを使用することをお勧めします。これが一般的な方法です)。

于 2012-12-29T12:30:05.457 に答える