2012-05-07 11 views
4

私のプログラムには、Entityという名前のクラスがあります。別のクラスのインベーダーはエンティティを継承します。私は4種類のインベーダーを使いたいので、インベーダーを継承するクラスInvader1、Invader2、Invader3、Invader4を宣言します。私は、実行時にエンティティ内の要素の型をチェックすると、それは、4種類のいずれかを返すことがあり派生クラスのタイプを確認してください

typeid(*entities->at(index)) 

言う

entities.push_back(new Invader4()); 
entities.push_back(new Invader3()); 
entities.push_back(new Invader2()); 
entities.push_back(new Invader1()); 
entities.push_back(new Invader0()); 

:今、私のようなすべてのインベーダーを保存するために、エンティティのポインタ型ベクトルを宣言します侵略者のエンティティには、エンティティを継承する他のオブジェクトもあります。だから私は、オブジェクトの種類がインベーダーかどうかをチェックしたいのですが、Invader1、Invader2などのようなものかどうかを知りたくありません。

どうすればいいですか?

+6

実行時にクラスを知る必要があることは、設計が悪いことを示します。実際に何をしようとしていますか? –

答えて

6

C++でこれを行うには多くの方法がありますが、基本的な問題は、ポリモーフィックであるはずのコンテナ内の要素をクエリし始める必要があるということです。多形要素のコレクションを持つことの全ポイントは、それらをすべて同じように扱うことができることです。したがって、vector<Entity*>がある場合は、その要素をEntity*として扱うだけです。EntityにあるInvaderのような関数を呼び出す必要がある場合は、Invader*というコンテナを保持する方がよい(元のコンテナと同じポインタを使用)。

+0

私は完全に同意します。これはliskovの原則の全ポイントです! – ltjax

+0

はい、あなたは正しいです。多型を使用しようとするときにタイプチェックを使用するのは恥ずかしいことです。いくつかのまれなケースでは、タイプをチェックしてオブジェクトの機能を別々にする必要があるようです。私のプログラムの構造を改善しようとしています。ヘルプのためのThx! – Tony

3

あなたがdynamic_cast<Invader*>(entities->at(index))戻るないNULL(ポインタがそのクラスInvaderから導出されたオブジェクトを指していない場合、それはNULLポインタをもたらすように)かどうかを確認できました。

一部のドキュメントについては、this linkを参照してください。

2

Entityを継承するInvaderクラスを作成します。 Invader1Invader2などのクラスをInvaderから継承してください。

その後、EntityfalseInvadertrueを返すvirtual bool IsInvader() const;を追加することができます。

+1

そして、 'Entity'から派生したクラスを書くたびに' Entity'に 'isWhatever()'を追加しますか? – juanchopanza

+0

@juanchopanza 'virtual const char * getClassName()const;'それでは? – moooeeeep

+1

@moooeeeepそれはほとんど悪いです。 "多型"コレクションの各要素を照会する必要がある設計では、多形性のすべての利点が失われ、スケーラビリティは全くありません。 – juanchopanza

1

通常、この質問をすると、実際にはインターフェイスに仮想関数がありません。あなたのようなものがある場合は

をあなたはほぼ確実にあなたのインベーダークラスで

virtual void tryInvade() {/* normally, entities don't invade*/} 
あなたのエンティティで

virtual void tryInvade() {invade(); /*but invaders do!*/} 

を追加することによって、それをリファクタリングすることができます。

もう1つの選択肢は、エンティティのタイプを決して「失うこと」ではありません。このような場合に仮想関数を使用したくない場合は、その基本クラスポインタを参照してそれらのエンティティを格納すべきではなく、実際に使用したいクラスへのポインタとして格納するべきです。つまり、エンティティのタイプを後で要求するのではなく、そのままにしておくだけです。これはおそらく、それぞれのストレージにliskov substition principleに違反していたため、継承を使用してはならないという兆候でしょう。

関連する問題