2010-04-26 36 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