2012-02-05 10 views
1

現在、C++でゲームのイベントパッシングシステムをプログラミングしています。イベントが論理的に互いに継承されていると便利です。継承階層を持つイベントを渡すためのC++システム

は、これは私が例えば(おそらく空の基底クラスEventから派生します)Explosionから派生したタイプNukeExplosionのイベントを、上げることができる意味し、それは同様に、タイプNukeExplosionのイベントにすべてのリスナーに渡さなるだろうより一般的なExplosionとして。同じイベントタイプへのリスナーのセットごとにイベントにdynamic_castを行う

  • は、これまでのところ私は2つの可能な解決策を考え出すことができました。それが成功すると、そのイベントをセット内のすべてのリスナーに渡すことができます。

  • イベントを再度発生させるが、より一般的なタイプのコードを各イベントタイプに追加する。このイベントは、リスナーのマップとともにtypeid演算子の結果を使用してリスナーに渡されます。

エラーが発生しやすく、すべてのイベントクラスにほぼ同じコードを書く必要があるため、2番目のオプションは本当に好きではありません。

最初のオプションの問題は、dynamic_castを大量に実行する必要がある可能性があることです。そのことを避けたいと思います。

私はこれまでに取り組んでいない方法がありますか、それとも私ができる最善の方法は何ですか?または、私はイベントの継承を完全に破棄すべきですか?

答えて

1

私はこの質問にほぼ正確にここに来ました。問題は、基本的には、eの動的型がExplosionEvent *であっても、handle (ExplosionEvent *e)のような関数は、eの静的型を受け入れないようにすることが問題です。それは素晴らしい機能ですが、それ以外の言語で何を変えなければならないかはわかりません。

Visitorパターンは、私が考えることができる最もクリーンなソリューションです。欠点は、それが冗長であり、dynamic_cast<>より安くない可能性があるということです。

Main.hpp:

#include <iostream> 

class Event; 
class Handler; 

#include "Event.hpp" 
#include "Handler.hpp" 

イベント。HPP:

#ifndef EVENT_H 
#define EVENT_H 

class Event 
{ 
public: 
    virtual void accept (Handler *handler) { } 
}; 

class ExplosionEvent : public Event 
{ 
    void accept (Handler *handler); 
}; 

#endif // !EVENT_H 

Event.cpp:

#include "Main.hpp" 

void 
ExplosionEvent::accept (Handler *handler) 
{ 
    handler->handleExplosion (this); 
} 

Handler.hpp:

#ifndef HANDLER_H 
#define HANDLER_H 

class Handler 
{ 
public: 
    void handle (Event *event) { event->accept (this); } 
    virtual void handleExplosion (ExplosionEvent *explosionEvent) { } 
}; 

class ExplosionHandler : public Handler 
{ 
    void handleExplosion (ExplosionEvent *explosionEvent); 
}; 

#endif // !HANDLER_H 

Handler.cpp:

#include "Main.hpp" 

void 
ExplosionHandler::handleExplosion (ExplosionEvent *explosionEvent) 
{ 
    std::cout << "BOOM!" << std::endl; 
} 

main.cppに:

#include "Main.hpp" 

int 
main (int argc, char *args) 
{ 
    Event *event = new ExplosionEvent; 
    Handler *handler = new ExplosionHandler; 
    handler->handle (event); 
} 

コンパイルして実行します。

$ g++ -o boom *.cpp 
$ ./boom 
BOOM! 
$ 
+0

私がすでに説明した第2のアプローチをすでに使用していましたが、私は実際にこの解決策が好きです。私が見ることができる唯一の問題は、ハンドラの多くのシステムではハンドラ内の空の機能は、おそらくかなり多く呼び出されるだろうということです。 – f4st

0

リスナーごとに動的なキャストを行うと、多数のリスナーにとって非常に高価になりますので、おそらくリスナーにtypeidのマップを実装する必要があります。

リスナーのHandleEventには、Eventというオブジェクトが必要です。このメソッドは、(static_castで)ベースイベントを予期しているイベントタイプにキャストします(イベント登録メカニズムのイベントディスパッチャを信頼する必要があります)。

またEventクラスを送信したくない場合があるため、有効な場合は新しいベースイベントを返すメソッドをEventクラスに実装します。これはマクロを使って行うことができますが、私はまだそれを動作させることができませんでしたが、テンプレートメソッドを使って行うこともできるという気持ちがあります。ディスパッチャは、イベントハンドラを呼び出す前にそのベースイベントを取得してから、ベースイベントのハンドラを呼び出します。

+0

をfeelthatでは、あなたが示唆されているものは、私は私の第二の選択肢として記述するものです。そして、私は私がピックアップ自体はすべてのイベント・クラスに類似したコードを追加する必要があり、それを好きではない、と述べました。面前に、早急に着陸してください。 – f4st

関連する問題