c++ - C++ 将包含多态属性的类对象存储在堆栈中
问题描述
我正在尝试从头开始制作国际象棋游戏,并在过去几个月中取得了重大进展。但是,我最近遇到了一个我无法弄清楚如何解决的问题。
代码(更新)
由于源代码太大,无法在此处发布,我认为最好留下我的 GitHub 帐户的链接,在那里可以找到它:https ://github.com/lbragile/chessCAMO
描述
棋
包含相关的游戏标志和转弯跟踪,并保留一堆棋盘位置以允许玩家撤消移动。
片
包含作品的:
- 正方形 ([0,63])
- 移动信息(用于易位和初始棋子移动)
- 类型
- 颜色
片类型类
包括:
- 典当
- 骑士
- 主教
- 车
- 女王
- 国王
- 空(用于空白方块)
这些继承自基类(Piece)
问题
通过这种设置,Chess和Piece是独立的类(一个不是从另一个派生的)。但是,为了跟踪堆栈中的棋盘位置,Chess类使用成员变量:
stack<vector<Piece*>> board_positions;
事实上,这确实允许我撤消该位置,甚至在之后进行移动。但是,在通过我的测试用例运行我的算法之后,我注意到它在涉及check、double check、checkmate 和 stalemate 标志的情况下失败了。当我检查我的 GUI 时,这一点得到了证实。例如,做出一个导致检查的动作,然后“撤消”该动作,并再次重复该动作。这失败了,因为没有存储前一个位置的检查标志。
这导致了一个明显的结论,即我必须在每次移动时存储整个 Chess 对象,以便获得棋盘表示和相应的必要标志。我只是不知道如何在Chess类中拥有一个可以将 Chess 对象存储在堆栈中的成员变量。主要原因是Chess本身包含Piece对象,这些对象是多态的(虚拟函数),并且两个类是分开的。
任何关于如何进行的建议或有用的提示将不胜感激。
编辑#1
我使用提供的建议更新了代码。但是,我目前的问题是板标志似乎没有在堆栈上更新。这似乎源于~Chess()
. 我认为它实际上并没有破坏对象指针,而是简单地弹出它们。我尝试使用从if 语句的函数中std::move()
移入资源并删除析构函数中的指针,但这似乎无法解决问题。makeMove(int src, int dest, istream &in)
temp_chess
pushInfo()
game_info
编辑#2
请参阅下面的答案,我使用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;
};
国际象棋.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;
}
感谢大家提供的帮助!
推荐阅读
- swift - 制作中间路线和最终路线?
- ios - 将视图锚定到主视图时出现自动布局错误 - Swift
- database - 如何根据数据设置firebase实时数据库规则?
- c - 将 Led 重置为 LOW 从 Visual Studio 到 arduino
- kotlin - Kotlin 接口实现“显式”
- tomcat - 启动 SAP hybris 服务器时出现 Jrebel 问题
- javascript - 如何使用 javascript 从 iframe 访问父级的 JSON 对象
- gpio - 为什么我的 linux i2c-gpio 驱动程序无法通过 acpi 模式探测设备
- .net - 在实体框架中动态选择连接字符串到主动可用的数据库
- typo3 - 站点地图在typo3 9.5.x 中不能真正工作