C++ 在堆栈中存储 class 个包含多态属性的对象
C++ Store class objects which contain polymorphic properties in a stack
我正在尝试从头开始制作国际象棋游戏,并在过去几个月取得了重大进展。但是,我最近遇到了一个我无法解决的问题。
CODE (UPDATED)
由于源码太大,post放在这里,我觉得最好留一个link到我的GitHub账号,在那里可以找到:https://github.com/lbragile/chessCAMO
DESCRIPTION
国际象棋
包含相关的游戏标志和回合跟踪,并保留 棋盘位置堆栈 以允许玩家撤消移动。
张
包含作品的:
- 平方 ([0,63])
- 移动信息(用于易位和初始棋子移动)
- 类型
- 颜色
片类型classes
包括:
- 棋子
- 骑士
- 主教
- 车
- 女王
- 国王
- 空(空白方块)
这些继承自基础class (Piece)
QUESTION
有了这个设置,Chess 和 Piece 是分开的 classes(一个不是从另一个派生的) .
但是,为了跟踪堆栈中的棋盘位置,Chess class 使用成员变量:
stack<vector<Piece*>> board_positions;
这实际上让我可以撤消头寸,甚至可以在之后进行操作。然而,在 运行 我的算法通过我的测试用例之后,我注意到它在涉及 检查、双重检查、将死和僵持 标志的情况下失败了。当我检查我的 GUI 时,这已得到确认。例如,
进行导致检查的移动,然后“撤消”该移动,然后再次重复该移动。由于未存储先前位置的检查标志,因此失败。
这导致了一个明显的结论,即我必须在每次移动时存储整个 Chess 对象,以便我同时获得 棋盘表示 和 相应的必要标志。我只是不知道如何在 class Chess 中有一个成员变量可以将 Chess 对象存储在堆栈中。主要原因是 Chess 本身包含 Piece 对象,这些对象是 polymorphic (虚函数)和两个 class 是 分开的 .
任何关于如何进行的建议或有用的提示将不胜感激。
EDIT #1
我根据提供的建议更新了代码。然而,我目前的问题是板 flags 似乎没有在堆栈上更新。这似乎源于~Chess()
。我认为它实际上并没有破坏对象指针,而是简单地弹出它们。我尝试在 if 语句的 pushInfo()
函数中使用 std::move()
将 makeMove(int src, int dest, istream &in)
中的资源从 temp_chess
中移动,并删除析构函数中的 game_info
指针,但是这似乎无法解决问题。
EDIT #2
请参阅下面的答案,我使用 Chess
对象的 serialization/de-serialization 解决了问题。
我设法通过 serializing/de-serializing 将 Chess
对象的私有成员添加到文件来解决问题。
我这样做的方法是创建一个单独的文件夹来存储这些文件,并向 Chess
添加一个移动计数私人成员。然后我使用重载的提取和插入运算符添加了序列化功能:
chess.h
class Chess
{
public:
// previous functions
// Accessor/mutator functions for number of moves made
int getNumMoves() { return num_moves;}
void setNumMoves(int num_moves) {this->num_moves = num_moves;}
// to serialize (write the object to a file)
friend ostream & operator << (ostream &out, const Chess &chess_object);
// to de-serialize (read in the object from a file)
friend istream & operator >> (istream &in, Chess &chess_object);
private:
// previous members
int num_moves;
};
chess.cpp
// puts each member field on a new line
ostream & operator << (ostream &out, const Chess &chess_object)
{
for(const auto & elem : chess_object.getBoard())
out << elem->getPieceType() << endl << elem->getPieceSquare() << endl << elem->getPieceColor() << endl
<< elem->getPieceMoveInfo() << endl << elem->getEnPassantLeft() << endl << elem->getEnPassantRight() << endl;
out << chess_object.getCheck() << endl << chess_object.getDoubleCheck() << endl << chess_object.getCheckmate() << endl << chess_object.getStalemate() << endl;
out << chess_object.getTurn() << endl;
return out;
}
istream & operator >> (istream &in, Chess &chess_object)
{
// delete the allocated memory and restore new data
vector<Piece*> board = chess_object.getBoard();
for(unsigned int i = 0; i < board.size(); i++)
delete board[i];
// board.clear();
string input;
for(auto & elem : board)
{
in >> input;
switch(input[0] - '0')
{
case 0:
elem = new Pawn(0, PAWN, NEUTRAL);
break;
case 1:
elem = new Knight(0, KNIGHT, NEUTRAL);
break;
case 2:
elem = new Bishop(0, BISHOP, NEUTRAL);
break;
case 3:
elem = new Rook(0, ROOK, NEUTRAL);
break;
case 4:
elem = new Queen(0, QUEEN, NEUTRAL);
break;
case 5:
elem = new King(0, KING, NEUTRAL);
break;
default:
elem = new Empty(0, EMPTY, NEUTRAL);
}
in >> input;
elem->setPieceSquare(stoi(input));
in >> input;
elem->setPieceColor((pieceColor) (input[0] - '0'));
in >> input;
elem->setPieceMoveInfo(input == "1");
in >> input;
elem->setEnPassantLeft(input == "1");
in >> input;
elem->setEnPassantRight(input == "1");
}
chess_object.setBoard(board);
in >> input;
chess_object.setCheck(input == "1");
in >> input;
chess_object.setDoubleCheck(input == "1");
in >> input;
chess_object.setCheckmate(input == "1");
in >> input;
chess_object.setStalemate(input == "1");
in >> input;
chess_object.setTurn((pieceColor) (input[0] - '0'));
return in;
}
感谢大家提供的帮助!
我正在尝试从头开始制作国际象棋游戏,并在过去几个月取得了重大进展。但是,我最近遇到了一个我无法解决的问题。
CODE (UPDATED)
由于源码太大,post放在这里,我觉得最好留一个link到我的GitHub账号,在那里可以找到:https://github.com/lbragile/chessCAMO
DESCRIPTION
国际象棋
包含相关的游戏标志和回合跟踪,并保留 棋盘位置堆栈 以允许玩家撤消移动。
张
包含作品的:
- 平方 ([0,63])
- 移动信息(用于易位和初始棋子移动)
- 类型
- 颜色
片类型classes
包括:
- 棋子
- 骑士
- 主教
- 车
- 女王
- 国王
- 空(空白方块)
这些继承自基础class (Piece)
QUESTION
有了这个设置,Chess 和 Piece 是分开的 classes(一个不是从另一个派生的) . 但是,为了跟踪堆栈中的棋盘位置,Chess class 使用成员变量:
stack<vector<Piece*>> board_positions;
这实际上让我可以撤消头寸,甚至可以在之后进行操作。然而,在 运行 我的算法通过我的测试用例之后,我注意到它在涉及 检查、双重检查、将死和僵持 标志的情况下失败了。当我检查我的 GUI 时,这已得到确认。例如, 进行导致检查的移动,然后“撤消”该移动,然后再次重复该移动。由于未存储先前位置的检查标志,因此失败。
这导致了一个明显的结论,即我必须在每次移动时存储整个 Chess 对象,以便我同时获得 棋盘表示 和 相应的必要标志。我只是不知道如何在 class Chess 中有一个成员变量可以将 Chess 对象存储在堆栈中。主要原因是 Chess 本身包含 Piece 对象,这些对象是 polymorphic (虚函数)和两个 class 是 分开的 .
任何关于如何进行的建议或有用的提示将不胜感激。
EDIT #1
我根据提供的建议更新了代码。然而,我目前的问题是板 flags 似乎没有在堆栈上更新。这似乎源于~Chess()
。我认为它实际上并没有破坏对象指针,而是简单地弹出它们。我尝试在 if 语句的 pushInfo()
函数中使用 std::move()
将 makeMove(int src, int dest, istream &in)
中的资源从 temp_chess
中移动,并删除析构函数中的 game_info
指针,但是这似乎无法解决问题。
EDIT #2
请参阅下面的答案,我使用 Chess
对象的 serialization/de-serialization 解决了问题。
我设法通过 serializing/de-serializing 将 Chess
对象的私有成员添加到文件来解决问题。
我这样做的方法是创建一个单独的文件夹来存储这些文件,并向 Chess
添加一个移动计数私人成员。然后我使用重载的提取和插入运算符添加了序列化功能:
chess.h
class Chess
{
public:
// previous functions
// Accessor/mutator functions for number of moves made
int getNumMoves() { return num_moves;}
void setNumMoves(int num_moves) {this->num_moves = num_moves;}
// to serialize (write the object to a file)
friend ostream & operator << (ostream &out, const Chess &chess_object);
// to de-serialize (read in the object from a file)
friend istream & operator >> (istream &in, Chess &chess_object);
private:
// previous members
int num_moves;
};
chess.cpp
// puts each member field on a new line
ostream & operator << (ostream &out, const Chess &chess_object)
{
for(const auto & elem : chess_object.getBoard())
out << elem->getPieceType() << endl << elem->getPieceSquare() << endl << elem->getPieceColor() << endl
<< elem->getPieceMoveInfo() << endl << elem->getEnPassantLeft() << endl << elem->getEnPassantRight() << endl;
out << chess_object.getCheck() << endl << chess_object.getDoubleCheck() << endl << chess_object.getCheckmate() << endl << chess_object.getStalemate() << endl;
out << chess_object.getTurn() << endl;
return out;
}
istream & operator >> (istream &in, Chess &chess_object)
{
// delete the allocated memory and restore new data
vector<Piece*> board = chess_object.getBoard();
for(unsigned int i = 0; i < board.size(); i++)
delete board[i];
// board.clear();
string input;
for(auto & elem : board)
{
in >> input;
switch(input[0] - '0')
{
case 0:
elem = new Pawn(0, PAWN, NEUTRAL);
break;
case 1:
elem = new Knight(0, KNIGHT, NEUTRAL);
break;
case 2:
elem = new Bishop(0, BISHOP, NEUTRAL);
break;
case 3:
elem = new Rook(0, ROOK, NEUTRAL);
break;
case 4:
elem = new Queen(0, QUEEN, NEUTRAL);
break;
case 5:
elem = new King(0, KING, NEUTRAL);
break;
default:
elem = new Empty(0, EMPTY, NEUTRAL);
}
in >> input;
elem->setPieceSquare(stoi(input));
in >> input;
elem->setPieceColor((pieceColor) (input[0] - '0'));
in >> input;
elem->setPieceMoveInfo(input == "1");
in >> input;
elem->setEnPassantLeft(input == "1");
in >> input;
elem->setEnPassantRight(input == "1");
}
chess_object.setBoard(board);
in >> input;
chess_object.setCheck(input == "1");
in >> input;
chess_object.setDoubleCheck(input == "1");
in >> input;
chess_object.setCheckmate(input == "1");
in >> input;
chess_object.setStalemate(input == "1");
in >> input;
chess_object.setTurn((pieceColor) (input[0] - '0'));
return in;
}
感谢大家提供的帮助!