2010-04-26 43 views
2

我只是在嘗試製作一個簡單的井字遊戲時遇到一些C++,並且遇到了一些問題。這是我的代碼:關於字符的C++初學者問題

#include <iostream> 
using namespace std; 

class Square { 
public: 
    char getState() const; 
    void setState(char); 
    Square(); 
    ~Square(); 
private: 
    char * pState; 
}; 

class Board { 
public: 
    Board(); 
    ~Board(); 
    void printBoard() const; 
    Square getSquare(short x, short y) const; 
private: 
    Square board[3][3]; 
}; 

int main() { 
    Board board; 
    board.getSquare(1,2).setState('1'); 
    board.printBoard(); 
    return 0; 
} 

Square::Square() { 
    pState = new char; 
    *pState = ' '; 
} 
Square::~Square() { 
    delete pState; 
} 
char Square::getState() const { 
    return *pState; 
} 
void Square::setState(char set) { 
    *pState = set; 
} 

Board::~Board() { 

} 
Board::Board() { 

} 
void Board::printBoard() const { 
    for (int x = 0; x < 3; x++) { 
     cout << "|"; 
     for (int y = 0; y < 3; y++) { 
      cout << board[x][y].getState(); 
     } 
     cout << "|" << endl; 
    } 
} 
Square Board::getSquare(short x, short y) const { 
    return board[x][y]; 
} 

原諒我,如果它存在公然明顯的問題,或者它愚蠢寫的,這是我在C++中第一個程序:P,但問題是,當我嘗試設置方1 ,2到字符'1',它不會打印出來作爲1,它會打印出一些我不認識的奇怪字符。

有誰能告訴我爲什麼? :)

在此先感謝。

+0

是否有原因需要在堆上使用char *而不是在堆棧上使用普通的'char'? – 2010-04-26 19:06:56

+0

這不是真的解決你的問題,但爲什麼你動態分配每個Square的狀態?爲什麼不只有一個字符字段?另外,你的getSquare應該返回一個正方形的引用,而不是按值返回。 – Uri 2010-04-26 19:07:20

+0

Xavier:只是在嘗試新的東西。 Uri:我真的不知道。我對此很陌生。 – Samwhoo 2010-04-26 19:21:14

回答

4
  1. 您不需要使用new來創建變量實例。

  2. 嘗試將您的狀態變量更改爲char而不是char *(指向char)。

  3. 通常,char *類型用於指示由nul字符終止的字符集合(數組)。

  4. 另外,setstd命名空間中的數據類型。只需將名稱更改爲其他名稱,例如new_value

  5. getState()方法返回副本的狀態,而不是對狀態的引用。這與Java和C++不同。嘗試返回State&,這是C++行話一個國家實例的引用。

  6. 你的程序是一個井字棋遊戲有點大材小用;在古代那些使用char,而不是所謂的OO這個新的老式的東西陣列。

+0

感謝您的回答:D 我知道做井字棋的OO版本有點矯枉過正,但我​​只是想習慣語言及其錯綜複雜。 – Samwhoo 2010-04-26 19:22:19

+0

@Sam,第4點是你避免使用名稱空間標準的一個很好的例子。 – Bill 2010-04-26 20:32:42

2

兩個問題:

1)getSquare方法是const等返回const對象。

1)getSquare方法爲const,因此不能返回非const的對象的非const引用。

2)從getSquare返回的對象是董事會廣場的副本。

要解決:

1)從getSquare方法卸下const

2)改變getSquare返回一個參考:Square & Board::getSquare(short x, short y)

+0

雖然最好只從const方法返回const引用,但添加cont限定符不會影響返回類型。 – 2010-04-26 19:14:21

+0

@John Gordon:g ++給了''const'類型'Square&'的引用的無效初始化,所以基本上是這樣,因爲你告訴方法'this'是'const',因此你不能初始化一個非const引用。 – 2010-04-26 19:23:16

+0

這是因爲您試圖將const引用用作非const函數,而不是因爲方法限定符更改了返回類型。考慮一個方法,該方法返回對除* this或成員變量(例如靜態成員)之外的其他內容的引用。 – 2010-04-26 19:28:40

5

Board::getSquare該方法返回Square對象的副本。被複制的Square對象的pState變量指向與原始Square對象相同的字符。當複製的對象被銷燬時,它將刪除pState變量指向的對象char。這會使中的Square對象中的char對象失效。當你去打印時,你正在打印一個無效的char對象。

正如其他人所說,pState變量應該可能是char而不是char*。這將使您在解決問題方面向前邁進一步。您仍然需要處理返回對象Square的引用,而不是Square對象的副本。

3
Square Board::getSquare(short x, short y) const { 
    return board[x][y]; 
} 

在這裏,你returing廣場實例的副本。由於沒有拷貝構造函數,實例將被存儲的值被複制。所以現在有2個Square實例,其狀態指向相同的值。

但廣場有析構函數。在析構函數中,狀態指針被刪除。但是剩下的副本現在擁有一個懸掛指針。

  1. 方形實例A已創建。
  2. 字符指針pA的被分配和設置爲' ',創建

    +-----+ 
    | pA -----> ' ' 
    +-----+ 
    
  3. 臨時廣場實例getSquare位複製。這意味着它的字符指針的pB點的同一位置pA的

    +-----+   
    | pA -----> ' ' 
    +-----+ ^
    +-----+  | 
    | pB --------' 
    +-----+ 
    
  4. 廣場實例是的setState到'1',所以Pb含量被改變爲'1'

    +-----+   
    | pA -----> '1' 
    +-----+ ^
    +-----+  | 
    | pB --------' 
    +-----+ *pB='1' 
    
  5. 臨時廣場實例被破壞,因爲,這是暫時的。

    +-----+   
    | pA -----> garbage 
    +-----+ ^
    + - - +  | 
    : pB --------' 
    + - - + delete pB 
    
  6. 現在pA的點垃圾。

    +-----+   
    | pA -----> garbage 
    +-----+ 
    

你應該返回reference避免複製,

Square& Board::getSquare(short x, short y) { return board[x][y]; } 
//----^ "&" means reference. Similar to pointer, but not rebindable/nullable. 
//  Just think of it as a read-only pointer without needing a "*" 

const Square& Board::getSquare(short x, short y) const { return board[x][y]; } 
// Both mutable and const versions are needed. (Yes, code duplication.) 

和/或提供一個拷貝構造函數。

class Square { 
public: 
    ... 
    Square(const Square&); 

... 
Square::Square(const Square& other) { 
    pState = new char; 
    *pState = *other.pState; 
} 

你可以使用

class Square { 
public: 
    char getState() const; // { return state; } 
    void setState(char); // { state = input; } 
private: 
    char state; 
}; 

,以避免堆內存搞亂。 cout <<支持打印char

請不要在Java中編寫C++。

+0

我的第一語言是Java,所以原諒轉換^ _^ – Samwhoo 2010-04-26 19:17:58

+0

明智的答案,謝謝你的解釋!就像我說的,對於所有這些仍然很新穎。 另一個問題:getState()方法返回char的副本,對吧?我可以改變它返回一個指針嗎?如果我這樣做,那會提高效率嗎? (我知道這只是60奇數行代碼,但我很想知道:)) 謝謝。 – Samwhoo 2010-04-26 19:29:20

+0

@Samwhoo:你*必須*將它改爲指針(或更好的參考),因爲你想改變原始值,而不是副本。查看如何更新。 (返回值elision(http://en.wikipedia.org/wiki/Return_value_optimization)通過指針(引用)或值返回不會影響效率。) – kennytm 2010-04-26 19:45:57