我正在尝试实现简单的国际象棋游戏。为此,我创建了所需的不同类。以下是各个类的示例代码。
piece.hpp(它有piece类的实现)
#include<bits/stdc++.h>
using namespace std;
class Piece {
public:
bool white = false;
bool killed = false;
bool isWhite() {
return white;
}
void setWhite(bool white) {
this->white = white;
}
bool isKilled() {
return killed;
}
void setKilled(bool killed) {
this->killed = killed;
}
virtual bool validMove() = 0;
};
class Pawn: public Piece {
bool validMove() {
return true;
}
public:
Pawn(bool white, bool killed) {
setWhite(white);
setKilled(killed);
}
};
cell.hpp(它具有板的每个单元的实现)
#include<bits/stdc++.h>
#include "piece.hpp"
using namespace std;
class Cell {
private:
Piece *piece;
int x, y;
public:
Cell() {}
Cell(int x, int y, Piece *piece) {
this->setPiece(piece);
this->setX(x);
this->setY(y);
}
Piece* getPiece() {
return this->piece;
}
int getX() {
return this->x;
}
int getY() {
return this->y;
}
void setPiece(Piece *p) {
this->piece = p;
}
void setX(int x) {
this->x = x;
}
void setY(int y) {
this->y = y;
}
};
board.hpp(它有棋盘的实现)
#include<bits/stdc++.h>
#include "cell.hpp"
using namespace std;
class Board {
public:
vector<vector<Cell>> cells;
public:
Cell createCell(Piece *p, int x, int y) {
Cell cell(x, y, p);
return cell;
}
Cell getCell(int x, int y) {
if (x < 0 || x > 7 || y < 0 || y > 7) {
cout << "Not a valid index";
}
return cells[x][y];
}
void resetBoard() {
cells.resize(8, vector<Cell>(8, Cell(-1, -1, NULL)));
Pawn p1(true, false);
Pawn p2(true, false);
cells[1][0] = createCell(&p1, 1, 0);
cells[1][1] = createCell(&p2, 1, 1);
for(int i = 2; i < 6; i++) {
for(int j = 0; j < 8; j++) {
cells[i][j] = createCell(NULL, i, j);
}
}
cout << getCell(1, 0).getPiece() << endl;
cout << getCell(1, 0).getPiece()->isKilled() << " " << getCell(1, 0).getPiece()->isWhite() << endl;
}
};
game.hpp(它具有游戏的实现,例如在棋盘中设置初始值)
#include<bits/stdc++.h>
#include "board.hpp"
using namespace std;
class Game {
public:
bool isCurrentMoveWhite;
Board board;
Game() {
board.resetBoard();
cout << board.getCell(1, 0).getPiece() << endl;
cout << board.getCell(1, 0).getPiece()->isKilled() << " " << board.getCell(1, 0).getPiece()->isWhite() << endl;
isCurrentMoveWhite = true;
}
};
int main() {
Game game;
}
现在我面临的错误是游戏构造函数中打印语句的值与我在 Resetboard() 中打印的值不同。棋盘上的数值与游戏中的数值是不同的。有人可以解释为什么对象的值随机变化(afaik)。
我尝试打印对象地址和成员变量地址,对象和成员变量的地址在任何地方都是相同的,但不知何故值却不同。
我的问题是
正如评论中已经提到的,问题是变量
p1
和p2
的生命周期。它们是局部变量,这意味着一旦超出范围(在本例中为 resetBoard
函数),它们就不再存在。你仍然可以尝试使用他们最后的地址,那里可能仍然有东西,但不能保证是相同的数据,而且非常不安全。
您在
createCell(&p1, 1, 0)
调用中所做的就是获取 p1 的地址,并将指向它的指针存储在比 p1 寿命更长的对象中。由于 cell
对象存在于类字段内,因此只要 board
存在,它就会继续存在(即直到 Game
存在,因为它是它的字段,并且存在到 main
函数结束) .
正如您所看到的,当您尝试调用
cout << board.getCell(1, 0).getPiece()
时,棋盘单元存在,但 pawn 不再是内存中的有效对象。然而,由于您存储了它们的指针,代码会尝试访问我们之前定位的内存,但结果未定义。
作为解决方案,您可能需要使用以下任一方法:
将 pawn 复制到单元格对象中。然后,无需在
Piece
中保留指向 cells
的指针,只需将 Piece
对象直接存储为字段即可。将棋子复制/移动到单元格中。
改用动态内存。创建 Piece 对象时,使用
new
运算符:
块* new_piece = 新块(...); 那么这个对象在你离开函数作用域后并不会失效,并且可以在以后被寻址。这里的问题是,您还需要在使用后释放该内存,这将需要您向析构函数添加一些代码。
与 2 相同,但使用智能指针(
std::unique_ptr<Piece>
或 std::shared_ptr<Piece>
)。与以前基本相同,但它会照顾内存,帮助您在使用后不会忘记删除对象,并添加了对所有权的有用限制(例如,只有一个对象可以拥有 unique_ptr)。
希望这有帮助!