对象的成员变量的值是随机变化的

问题描述 投票:0回答:1

我正在尝试实现简单的国际象棋游戏。为此,我创建了所需的不同类。以下是各个类的示例代码。

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)。

我尝试打印对象地址和成员变量地址,对象和成员变量的地址在任何地方都是相同的,但不知何故值却不同。

我的问题是

  1. 解释为什么这些值会改变?
  2. 有人可以尝试解释如何在不改变代码的情况下使用resetboard()在板类中设置相同的值吗?
c++ oop abstract-class
1个回答
0
投票

正如评论中已经提到的,问题是变量

p1
p2
的生命周期。它们是局部变量,这意味着一旦超出范围(在本例中为
resetBoard
函数),它们就不再存在。你仍然可以尝试使用他们最后的地址,那里可能仍然有东西,但不能保证是相同的数据,而且非常不安全。

您在

createCell(&p1, 1, 0)
调用中所做的就是获取 p1 的地址,并将指向它的指针存储在比 p1 寿命更长的对象中。由于
cell
对象存在于类字段内,因此只要
board
存在,它就会继续存在(即直到
Game
存在,因为它是它的字段,并且存在到
main
函数结束) .

正如您所看到的,当您尝试调用

cout << board.getCell(1, 0).getPiece()
时,棋盘单元存在,但 pawn 不再是内存中的有效对象。然而,由于您存储了它们的指针,代码会尝试访问我们之前定位的内存,但结果未定义。

作为解决方案,您可能需要使用以下任一方法:

  1. 将 pawn 复制到单元格对象中。然后,无需在

    Piece
    中保留指向
    cells
    的指针,只需将
    Piece
    对象直接存储为字段即可。将棋子复制/移动到单元格中。

  2. 改用动态内存。创建 Piece 对象时,使用

    new
    运算符:

    块* new_piece = 新块(...); 那么这个对象在你离开函数作用域后并不会失效,并且可以在以后被寻址。这里的问题是,您还需要在使用后释放该内存,这将需要您向析构函数添加一些代码。

  3. 与 2 相同,但使用智能指针(

    std::unique_ptr<Piece>
    std::shared_ptr<Piece>
    )。与以前基本相同,但它会照顾内存,帮助您在使用后不会忘记删除对象,并添加了对所有权的有用限制(例如,只有一个对象可以拥有 unique_ptr)。

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.