在 C 中对指向对象的指针使用方法

Posted

技术标签:

【中文标题】在 C 中对指向对象的指针使用方法【英文标题】:Using methods on pointers to objects in C 【发布时间】:2012-07-15 21:29:26 【问题描述】:

我正在尝试制作 Minesweeper 的控制台版本,但在编辑板上的特定单元格时遇到了一些困难。如您所见,我有一个 Board,它有一个私有的 [6][6] Cell 对象数组。

目前,我正在尝试使用类似的方式调用 Cell 方法 Board gameBoard; gameBoard.accessCell(row,col).flag(); 但这似乎实际上并不是在编辑访问的 Cell 的状态,因为正在复制对象而不是指针。如何修复 Board::accessCell(int row, int col) 以返回指向对象的指针,以便我可以调用函数并实际编辑其状态?

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <iomanip>
#include <string>
using namespace std;

#define debugging true //set this to true to activiate debugging

const int ROWS(6), COLS(6), MINE(-1);
const char FLAG('F'), REVEALED('R'), HIDDEN('*');

class Cell

    friend class Board;
    private:
        char displaySetting;
        int minesTouching;
    public:
        Cell();
        int getMinesTouching() const;
        void increaseMinesTouching();
        char getDisplaySetting() const;
        bool isMine() const;
        void flag();
        void reveal();
        void setMine();
;
int Cell::getMinesTouching() const  return this->minesTouching; 
void Cell::increaseMinesTouching()  this->minesTouching++; 
char Cell::getDisplaySetting() const  return this->displaySetting; 
bool Cell::isMine() const  return this->minesTouching == MINE; 
void Cell::flag()  this->displaySetting = FLAG; 
void Cell::reveal()  this->displaySetting = REVEALED; 
void Cell::setMine()  this->minesTouching = MINE; 
Cell::Cell():
    displaySetting(HIDDEN),
    minesTouching(0)


class Board

    private:
        Cell boardCells[ROWS][COLS];
    public:
        Board();
        bool isInBounds(int row, int col) const;
        void reveal(int row, int col);
        void displayBoard() const;
        Cell accessCell(int row, int col) const;
;
Board::Board()

    //place mines randomly
    srand(time(0));
    for(int i=0; i<6;)
    
        int row = rand()%6, col = rand()%6;
        if(!this->boardCells[row][col].isMine())
        
            this->boardCells[row][col].setMine();
            i++;
        
    

    //determine number of mines touching each space and store them
    for(int i=0; i<ROWS; i++)
    
        for(int j=0; j<COLS; j++)
        
            if(!boardCells[i][j].isMine())
            
                if(boardCells[i+1][j+1].isMine())   boardCells[i][j].increaseMinesTouching(); //bottom right
                if(boardCells[i-1][j-1].isMine())   boardCells[i][j].increaseMinesTouching(); //top left
                if(boardCells[i+1][j+0].isMine())   boardCells[i][j].increaseMinesTouching(); //down
                if(boardCells[i+0][j+1].isMine())   boardCells[i][j].increaseMinesTouching(); //right
                if(boardCells[i-1][j-0].isMine())   boardCells[i][j].increaseMinesTouching(); //up
                if(boardCells[i-0][j-1].isMine())   boardCells[i][j].increaseMinesTouching(); //left
                if(boardCells[i+1][j-1].isMine())   boardCells[i][j].increaseMinesTouching(); //bottom left
                if(boardCells[i-1][j+1].isMine())   boardCells[i][j].increaseMinesTouching(); //top right
            
        
    

bool Board::isInBounds(int row, int col) const

    if(row < 0) return false;
    if(row >= ROWS) return false;
    if(col >= COLS) return false;
    if(col < 0) return false;
    return true;

void Board::reveal(int row, int col)

    if(!this->boardCells[row][col].getMinesTouching())
    
        this->boardCells[row][col].reveal();
            if(isInBounds(row+1, col+1))    this->reveal(row+1, col+1); //bottom right
        if(isInBounds(row-1, col-1))    this->reveal(row-1, col-1); //top left
        if(isInBounds(row+1, col+0))    this->reveal(row+1, col+0); //down
        if(isInBounds(row+0, col+1))    this->reveal(row+0, col+1); //right
        if(isInBounds(row-1, col-0))    this->reveal(row-1, col-0); //up
        if(isInBounds(row-0, col-1))    this->reveal(row-0, col-1); //left
        if(isInBounds(row+1, col-1))    this->reveal(row+1, col-1); //bottom left
        if(isInBounds(row-1, col+1))    this->reveal(row-1, col+1); //top right
    

void Board::displayBoard() const

    system("clear");
    if(debugging) //display system board if debugging is enabled
    
        for(int i=0; i<ROWS; i++)
        
            for(int j=0; j<COLS; j++)
                cout << "[ " << setw(3) << this->boardCells[i][j].getMinesTouching() << setw(3) << " ]";
            cout << "\n";
        
        cout << "\n\n\n";
    

    //
    for(int i=0; i<ROWS; i++)
    
        for(int j=0; j<COLS; j++)
        
            if(this->boardCells[i][j].getDisplaySetting() == HIDDEN)
                cout << "[ " << setw(3) << this->boardCells[i][j].getDisplaySetting() << setw(3) << " ]";
            else if(this->boardCells[i][j].getDisplaySetting() == REVEALED)
                cout << "[ " << setw(3) << this->boardCells[i][j].getMinesTouching() << setw(3) << " ]";
            else
                cout <<"[ " << setw(3) << FLAG << setw(3) << " ]";
        
        cout << "\n";
    
    cout << "\n";

Cell Board::accessCell(int row, int col) const  return this->boardCells[row][col]; 

//function prototypes
void provideMenu();
string playTurn(Board gameBoard, int& guesses);
void playGame();

int main()

    Board gameBoard;
    provideMenu();
    return 0;


void provideMenu()

    int choice(0);
    while(choice < 1 || choice > 3)
    
        cout << "1:\t Play a game of Minesweeper" << endl;
        cout << "2:\t Help" << endl;
        cout << "3:\t Exit" << endl;
        cin>>choice;
    
    switch(choice)
    
        case 1:
            playGame();
            break;
        case 2:
            cout << "The objective of Minesweeper is to clear all the tiles on the board without mines without uncovering any hidden mines" << endl;
            cout << "*\t Hidden tile, has yet to be revealed" << endl;
            cout << "F\t Flagged tile, marked by user as possible mine" << endl;
            cout << "#\t Any number represents the number of mines touching the tile" << endl;
            break;
    


void playGame()

    Board gameBoard;
    int guesses(0);
    string gameState = "onGoing";
    while(gameState == "onGoing")
    
        gameState = playTurn(gameBoard, guesses);
        if(gameState == "userWon")
            cout << "Congratulations, you've one!" << endl;
        if(gameState == "userLost")
        
            cout << "Game over! Try again!" << endl;
            gameBoard.displayBoard();
        
    


string playTurn(Board gameBoard, int& guesses)

    gameBoard.displayBoard();

    int row;
    do
    
        cout << "Row:";
        cin>>row;
     while(row <0 || row >= ROWS);

    int col;
    do
    
        cout << "Column:";
        cin>>col;
     while(col < 0 || col>= COLS);

    if(gameBoard.accessCell(row, col).isMine())
        return "userLost";
    if(++guesses == ROWS*COLS-6)
        return "userWon";
    gameBoard.reveal(row,col);
    return "onGoing";

【问题讨论】:

对于 Stack Overflow 问题来说,这代码太多了。请创建一个小得多的测试用例来代表您的问题。 您的构造函数对不存在的对象调用isMine,因为它们超出了数组的范围。 【参考方案1】:

您已经定义了返回副本的访问方法:

    Cell accessCell(int row, int col) const ;

由于您希望能够修改返回的Cell,因此您应该返回一个引用,并且方法不应该是const

    Cell & accessCell(int row, int col);

也需要对方法的实现进行相应的更改。

Cell & Board::accessCell(int row, int col)  return this->boardCells[row][col]; 

【讨论】:

【参考方案2】:

返回对 Cell 对象的引用而不是副本:

const Cell& Board::accessCell(int row, int col) const

    return this->boardCells[row][col];

如果你需要mutable版本(非const),那么我会提示你需要重载这个函数。

【讨论】:

以上是关于在 C 中对指向对象的指针使用方法的主要内容,如果未能解决你的问题,请参考以下文章

Swift中对C语言接口缓存的使用以及数组字符串转为指针类型的方法

c ++如何获取指向另一个类中的当前对象的指针?

指向函数对象的成员函数指针

指针常量&常量指针&指向常量的指针常量

C ++在向量迭代中删除并返回指向对象的指针

c语言常量指针赋值给变量指针导致警告