1

C++ でチェス ゲームを作成しようとしています。

基本クラスの gamePiece と派生クラスの rook があります。私の最初のアイデアは、gamePiece オブジェクトのベクトルを作成し、そこにさまざまなタイプの gamePiece (ルーク、クイーン、ポーン) をすべて挿入することでした。前回の質問で分かったように、それはできません。gamePiece ベクトルは基本クラス (つまり、gamePiece) オブジェクトしか取りません。

ただし、スマート ポインターやその他の手法が提案されました。すぐに試してみます。

しかし、以下の手法が機能しない理由についてはまだ興味があります。代わりに、gamePieces へのポインターのベクターを作成し、そのベクター内に派生オブジェクトへのポインターを格納しようとするとどうなるでしょうか?

vector<gamePiece *> vectorOfPointersToGamePieces;  
vector<gamePiece *>::iterator itOfPointersToGamePieces;

たとえば、上記のベクター内の最初の位置に rook オブジェクトへのポインターを挿入するとします。最初に私がうまくいくかもしれないと思ったのは、この戦略でした:

vectorOfPointersToGamePieces.push_back( &(rook(1, "Rook", 'A', 1, "White", "Up")  ) );
itOfPointersToGamePieces=vectorOfPointersToGamePieces.begin();  
( * ( * (itOfPointersToGamePieces))).displayPieceInfo();

コンストラクターは正常に動作しているように見え、すべてが初期化されます。しかし、cout を使用してデータ メンバーの値を画面に表示すると、変数が空または初期化されているように見えます。彼らが姿を消したようです。

私の 2 番目のクラックは、このように、ルーク ポインターをゲームピース ポインターに動的にキャストしてから、ベクターに挿入することでした。

vectorOfPointersToGamePieces.push_back( dynamic_cast <gamePiece *> (&(rook(1, "Rook", 'A', 1, "White", "Up")  ) ) );

しかし、それは上記とまったく同じ出力をもたらしました。空/初期化された変数。

3 回目の試行では、一歩下がって、より簡単な操作を試みました。ここでは、ルークへのポインターの代わりに、gamePiece へのポインターをベクターに挿入しようとしました。

vectorOfPointersToGamePieces.push_back( &(gamePiece(1, "Rook", 'A', 1, "White", "Up")) );

この 3 番目の操作でも問題がありました。表示操作を試みたときに、コンストラクターで初期化した一部の変数のみが保持されていました。

itOfPointersToGamePieces=vectorOfPointersToGamePieces.begin();
( * ( * (itOfPointersToGamePieces))).displayPieceInfo();

具体的には、int と char が保持され、適切に表示されました。しかし、文字列は空っぽで消えてしまいました。

私の戦略がうまくいかない理由について何か考えがある人はいますか?

4

5 に答える 5

1

問題は、一時オブジェクトのアドレスを取得してに保存している場合std::vector、そのオブジェクトが破棄され、無効なオブジェクトを指しているままになることです。

rook(1, "Rook", 'A', 1, "White", "Up")でアドレスを取得してに入れる一時rookオブジェクトを作成します。その一時的なものは行の終わりまでになくなり、ポインターはぶら下がったままになります。そのポインターでほとんど何でもすると、未定義の動作が発生します。&push_backvectorOfPointersToGamePiecesrookvectorOfPointersToGamePieces

rookおそらく、次のようにオブジェクトを動的に割り当てる必要があります。

vectorOfPointersToGamePieces.push_back(new rook(1, "Rook", 'A', 1, "White", "Up"));

ただし、使い終わったら確認する必要がありますdeletestd::shared_ptrこれが、人々が(または)を使用するように言った理由ですstd::unique_ptr。があれば、上記の行を実行でき、オブジェクトの ingstd::vector<std::shared_ptr<gamePiece>>について心配する必要はありません。delete

ところで、a にstd::vector<gamePiece*>asという名前を付けるのvectorOfPointersToGamePiecesは少しばかげているように思えますね。変数の名前は、その基礎となる型ではなく、抽象的な問題レベルでそれが何であるかを説明することになっています。と呼んだほうがいいでしょうgamePieces

于 2013-02-18T21:46:30.663 に答える
0

ピースの数は少なく固定されているので、作成するだけです。次に、それらのアドレスをベクトルに入れます。スマートポインターは必要ありません。

rook white_kings_rook(/* whatever */);
// ...

std::vector<game_piece*> whites_pieces;
whites_pieces.push_back(&white_kings_rook);
于 2013-02-18T22:04:53.797 に答える
0

一時オブジェクトのアドレスをプッシュしています。そのポインターを取得して逆参照するまでに、一時的なものは無効になります。

これは未定義の動作です。

オブジェクトを永続化する必要があります。オブジェクトを で割り当てるか、new必要な期間有効なスコープで静的に作成します。

于 2013-02-18T21:46:20.387 に答える
0

現在、一時オブジェクトのアドレスをベクターに格納しています。そのステートメントの実行が終了するとすぐに、一時オブジェクトが破棄されるため、ポインターは無効になります。これらのポインターを逆参照しようとすると、未定義の動作が発生します。

ベクトルにポインターを格納する場合は、 のようにオブジェクトを動的に割り当てる必要がありますnew。つまり、次のように置き換えます。

[your_vector].push_back( &(rook(1, "Rook", 'A', 1, "White", "Up")

と:

[your_vector].push_back(new rook(1, "Rook", 'A', 1, "White", "up"))

定義された動作が得られます。これを行うことを実際に推奨しているわけではないことに注意してください。(明らかに) すでに言われているように、おそらく何らかのスマート ポインターを使用する必要があります (たとえば、std::unique_ptrこの場合は妥当と思われます)。ただし、これにより、未定義の動作が取り除かれます。メモリを手動で管理する仕事が残るだけであり、これは避けたほうがよいでしょう。

于 2013-02-18T21:46:45.577 に答える