7

私は自分のプロジェクトのためにシンプルなゲームデザインを構築しています。私は次のクラスを持っています:

class Character
{
public: 
   virtual void Display();
   virtual void SetParameters( char* param, ... );
};

class NonPlayableCharacter : public Character
{

public:
   virtual void Display();
   virtual void SetParameters( char* paaram, ... );
   int GetNPCState();
}

そして、CharacterまたはNonPlayableCharacterのいずれかから派生したクラスがたくさんあります。私はそれを次のように定義します:

std::vector<Character*> _allChar;

私の問題は、いつでもベクトルの要素の1つに対して何らかの操作を実行したいということです。GetNPCState()したがって、ベクトルから要素を取得することは、ベクトル内の要素がCharacter *タイプであるため、メソッドを直接呼び出すことはできません。だからこれを行う:

_allChar[0]->GetNPCState();

動作しません。だから私は有名なdynamic_castでそれをやってみました:

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
test->GetNPCState();

この最後の試みの問題はGetNPCState()、オブジェクトがnullであるためにクラッシュすることです。また、(デバッグを介して)_allChar[0]がnullではないことを知っています。

4

7 に答える 7

6

C ++(4)にはいくつかの種類のキャストがあり、そのうち2つがここで重要です。

  • static_castあなたが何をしているのか知っていると仮定します
  • dynamic_cast実行時に、あなたが正しく「推測」したことを確認します

注:dynamic_castクロスキャストや仮想ベースを含むキャストも可能になるため、簡略化されています。

dynamic_castターゲットの性質に応じて、実際には3つのバージョンがあります。

  • ターゲットが参照(つまりdynamic_cast<T&>(u))の場合、チェックが失敗すると例外がdynamic_castスローされますstd::bad_cast
  • ターゲットがポインタ(つまりdynamic_cast<T*>(p))の場合、チェックが失敗dynamic_castするとnullポインタが返されます
  • 最後に、特別な場合として、ターゲットがvoid*、の場合、dynamic_cast代わりに完全なオブジェクトのアドレスを返します

この場合、次のことができます。

  • dynamic_cast<NonPlayableCharacter*>(_allChar[0])->getNPCState()からに 切り替えてdynamic_cast<NonPlayableCharacter&>(*_allChar[0]).getNPCState()、例外を伝播させます
  • キャストの結果(NonPlayableCharacter* testここ)がnullでないかどうかをテストします
于 2012-10-22T14:40:38.420 に答える
5

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);

であるかどうかを確認する必要testがありNULLます。_allChar[0]がNULLでない場合でも、それが指すオブジェクトが。でない場合は、dynamic_castを返すことができます。NULLNonPlayableCharacter

したがって、正しいバージョンは次のようになります。

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if (test)
{
   test->GetNPCState();
}
于 2012-10-22T14:22:03.803 に答える
3

dynamic_castNULLキャストが不可能な場合に戻ります。中身を確認してください_allChar[0]getType()whereがオブジェクトの事前定義されたタイプIDを返すような関数を作成してから、次を使用できstatic_castます。

if (_allChar[0]->getType() == TYPE_NO_PLAYER) {
    static_cast<NonPlayableCharacter*>(_allChar[0])->getNpcState();
}
于 2012-10-22T14:21:44.607 に答える
2

dynamic_cast成功するかどうかをテストする必要があります。失敗するとnullポインタを返します。

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if (test) test->GetNCPState();

問題は、最初の要素がオブジェクトを指していないことである可能性がありNonPlayableCharacterます。

于 2012-10-22T14:22:49.187 に答える
2

dynamic_castNULL引数がaを指していない場合に戻りますNonPlayableCharacter(したがって、配列の最初の要素はおそらく他のサブクラスを指しています)-したがって、キャスト後Characterにチェックする必要があります。NULLただし、を使用dynamic_castすると、設計上の問題が発生する可能性があります。Characterおそらく、代わりに、たとえばと呼ばPerformMainActionInGameLoop()れ、さまざまなサブクラスで適切にオーバーライドされる仮想メソッドを使用する必要がありますか?

于 2012-10-22T14:22:59.217 に答える
2

ベースポインタから子ポインタを取得するには、を使用する必要がありますdynamic_cast。その動作は次のとおりです。

  • ポインタがChild*割り当てられたをnew Child指している場合dynamic_cast<Child*>は、Child*
  • ポインタが他のものを指している場合は、をdynamic_cast返しますNULL

問題は、で割り当てなかったnewか、オブジェクトのタイプが異なることです。

于 2012-10-22T14:23:06.437 に答える
2

dynamic_castを使用する方がおそらくより良いOOソリューションがありますが、このキャストを使用することの全体的なポイントは、キャストが失敗した場合にNULLポインターを返すことです。

したがって、GetNPCState()を呼び出す前に、NULLを確認してください。

NonPlayableCharacter* test = dynamic_cast<NonPlayableCharacter*>(_allChar[0]);
if( test != NULL )
{   
     test->GetNPCState(); 
}
于 2012-10-22T14:23:16.310 に答える