2016-05-17 11 views
0

私はクラス のrpgゲームで作業しています。インスタンスを格納するActionList *を持つ構造体呼び出しCharacterを作成しました。 GeneralPlayerは、他のプレーヤークラスが継承されているクラスです。 これは私のヘッダファイルです:私はvoid *にGeneralPlayer *を変換しようとしていたクラスへのポインタ*

class Battle 
{ 
public: 
     struct Character 
     { 
     char type;//monster or player? 
     bool alive; 
     void*instance;//pointer to instance 
     }; 
     Battle(GeneralPlayer*,AbstractMonster*,int,int,int);  
     Battle(GeneralPlayer*, AbstractMonster*, int, int); 
private: 
     Character *ActionList; 
}; 

。しかし、コードは私が思ったように動作しないようです。 PおよびMは、それらのプレーヤクラスのポインタの配列である。

Battle::Battle(GeneralPlayer*P, AbstractMonster*M, int a, int b, int c) 
{ 
    a = numP; 
    b = numM; 
    c = turn_limit; 
    ActionList = new Character[numP + numM]; 
    P = new GeneralPlayer[numP]; 
    for (int i = 0; i < numP; i++) 
    { 
     ActionList[i] = static_cast<void*>(P[i]); 
     ActionList[i].type = 'p'; 
    } 
    for (int i = numP; i < numP+numM; i++) 
    { 
     ActionList[i] = static_cast<void*>(M[i]); 
     ActionList[i].type = 'm'; 
    } 
} 

エラーC2440が表示され続けます。誰もが私の問題を解決することができれば幸いです。

+3

'P [i]'は 'GeneralPlayer *'ではなく 'GeneralPlayer'です。 – songyuanyao

+0

関数を呼び出した後、 'P'として渡した変数は初期化されていないようですか?詳しくは試してみてください。そして、私たちに示すために、[最小、完全で、かつ実証可能な例](http://stackoverflow.com/help/mcve)を作成してみてください。 –

+0

@songyuanyao申し訳ありません私はまだ初心者です。 P [i]がGeneralPlayer *でない場合は、どうすればよいでしょうか? –

答えて

4

一つCharacter構造がGenericPlayerまたはAbstractMonsterどちらかの親ではないということです。あなたのコードは、これは、その後、選手のリストがすでにBattleコンストラクタの呼び出し元によって初期化されていることを想定している

ActionList[i].type = 'p'; 
ActionList[i].alive = true; 
ActionList[i].instance = &P[i]; 

のようなものであるべきことを意味する、Character::instanceメンバーはプレイヤーやモンスターを指すべきであると思われます新しいプレイヤーの配列を割り当てるべきではないので、P = new GenericPlayer[numP];ステートメントを削除する必要があります。

"generic pointer"(what void *)を実際に指していると言ったメンバーは、悪いデザインとみなされます。代わりに、モンスターとプレイヤーの両方に共通の基本クラスを用意し、それを指すポインターを使用します。次に、多型virtualメンバー関数を正しく使用すると、typeフィールドは必要ありません。そして、プレイヤーやモンスターが生きているかどうかを伝える他の手段を使用するコードをリファクタリングするのは簡単ですし、Battle::Characterクラスはまったく必要なく、共通基底クラスへのポインタの配列を使うことができます代わりにコードを少し簡略化して、保守性に非常に優れています。


コードを表示する際に問題がいくつかあります。実行時に問題が発生することがあります。

一つの問題は、モンスターをループの反復では、あなたがnumP + numMまでnumPとループにoを初期化するが、配列MnumP + numMの要素が含まれていない場合は、境界の外に行こうということです。

代わりに、私はあなたに教えてください。

for (int i = 0; i < numM; i++) 
{ 
    ActionList[i + numP].type = 'm'; 
    ActionList[i + numP].alive = true; 
    ActionList[i + numP].instance = &M[i]; 
} 
+0

私の関数は、他のクラスのポインタをそれに渡すことです。 –

+0

@ShiYiLee関数 'void f(int a){a + = 5; } '。今、 'f(some_int_variable)'と言う関数を呼び出すと、 'some_int_variable'が変わると思いますか?これは 'Battle'コンストラクタ関数のポインタ変数' P'と同じです。 'P'はローカル変数です。' P'のすべての変更は関数内部でのみ行われます。 'P'(' P = new ... ')に代入すると、それは関数の中だけにあり、呼び出しで使用する変数は変更されません。 –

+0

@ShiYiLee前のコメントで説明した問題は、 'P'を参照渡しすることで解決しました。変更は非常に単純です:' Battle(GenericPlayer *&P、...) '。アンパサンド( '&')を追加すると 'P * a * reference * 'が' GenericPlayer'へのポインタになります。 –

5

オブジェクトをポインタに変換しようとしていますが、&演算子を使用して問題のポインタを取得してください。ここでの問題の

ActionList[i] = (void*)&P[i]; 
ActionList[i] = (void*)&M[i]; 
+0

明示的な(そしてCスタイルの)キャストは必要ありません。すべてのデータポインタ型は暗黙的に 'void * 'にキャストすることができます – StoryTeller

+0

また、Character * ActionListはデータ型Character **、Character ** ActionList = new Character * [numP + numM]でなければなりません。 –

+0

これは当てはまりますが、質問に答えることはできません( 'ActionList [i] .instance =(void *)&P[i];')、またはOPの問題を解決しません。さらに、なぜコンパイラがあなたのために行うことができるタイプチェックの良さをすべて破棄したいのですか? – user4581301

関連する問題