我开始自学C ++并且一直在尝试写一个二十一点程序。我正在尝试使用类来表示卡片,卡片和手。我相信除了dealCardToHand()
方法之外,目前为止所有程序都在使用。
void dealCardToHand(deck& d, hand& h){
h.setCard(h.getCardsInHand(), d.dealCard());
h.setCardsInHand(h.getCardsInHand() + 1);
}
似乎正确地递增了手中的牌数,但没有使用正确的数据调用setCard()
方法。任何帮助,将不胜感激。我包括相关的类和方法:
class deck{
int topCard;
card * cards[52];
public:
deck();
void shuffle();
void printDeck();
card dealCard();
};
card deck::dealCard(){//returns top card of deck and increments top card one
return *cards[topCard++];
}
class hand{
card * handCards[12];
int cardsInHand;
public:
hand();
card getCard(int i){ return *handCards[i]; }
void setCard(int i, card c) { handCards[i] = &c; }
int getCardsInHand() { return cardsInHand; }
void setCardsInHand(int i) { cardsInHand = i; }
void printHand();
};
答案 0 :(得分:4)
这很危险(可能至少是你问题的一部分):
void setCard(int i, card c) {handCards[i]=&c;}
此处,setCard(...)
按值传递card
个对象。这意味着在临时位置创建了呼叫者card
的新副本。这是c
作用的副本(setCard()
)。通过设置handCards[i]=&c;
,可以保存此临时对象的位置。但是当setCard()
返回时,该临时对象不再有效。
然后你继续在handCards[i]
中取消引用getCard()
。这会产生未定义的行为。从理论上讲,你应该期待恶魔开始从你的鼻子里飞出来。在实践中,您将看到从getCard()
返回的总垃圾。或者崩溃。或者,如果你太不走运,最后一个值会传递到setCard()
。
总的来说,看起来你用指针快速而松散地玩耍。我建议用两种方法之一解决问题:
当然,这些并不是唯一的选择,但它们可能会让你的生活更加轻松。
答案 1 :(得分:0)
正如其他人所指出的那样,问题在于您将临时变量的地址存储在指针变量中,并在临时变量超出范围(并已被删除)后取消引用该指针变量。
允许我的回答更多地进入摘要:
在C ++中,我们区分值类和多态类。你会发现它们的名称不同,你也会发现两者之间的区别并不像人们想的那么尖锐,但它大致是这样的:
值类实例在其状态中彼此不同。如果两个实例的状态相等,则实例的行为也将相等。
值类的示例是std::string
,所有STL容器,std::complex<>
等。
您可以像使用int
一样使用它们:您在堆栈中创建它们:
std::string s = "Hello, World"; // NOT std::string * s = new std::string;
按价值汇总:
class Widget {
std::complex<double> m_value; // NOT std::complex<double> * m_value;
public:
// ...
};
你通常可以比较它们是否相等,复制它们,存储它们 容器:
std::vector<std::string> vec;
std::string s = "Hello, World";
assert( s == "Hello, World" );
vec.push_back( s );
并且,与你的问题最相关的是,你通过(const-)引用(或者通过值,特别是如果它们非常小)传递它们,并且你也按值返回它们:
void func(const std::vector<double> & vec); // ok, just reading 'vec'
void func(std::vector<double> & vec); // ok, possibly writing to 'vec'
void func(std::vector<double> vec); // not so good, expensive in C++03; ok in C++11 in some situations
std::vector<double> func(); // ok, return value optimisation (look it up!) will make this fast
多态类的行为不同,而不是状态。多态类的两个实例可能具有相同的状态,但仍然表现完全不同。多态类可能的状态也不同,但重点在于它们的行为。这就是OOP(面向对象编程)的全部内容。
借用着名的C ++库“Qt”中的示例类,QLineEdit
和QPushButton
都是QWidget
。它们可能具有相同的状态(大小,位置......),但当您用鼠标点击它们时会发生什么情况完全不同。
在C ++中,要使用多态行为,必须调用虚拟函数,并且必须通过指针或对公共基类的引用(上面的QWidget
)来实现。因此,多态类通常在堆上分配:
QLineEdit * le = new QLineEdit();
QPushButton * pb = new QPushButton();
QWidget * leAsWidget = le; // works
QWidget * pbAsWidget = pb; // works
并存储并传递(智能)指针变量:
class MyWidget : public QWidget {
QLineEdit * m_lineEdit;
QPointer<QPushButton> m_pushButton; // QPointer is a smart pointer
public:
// ...
};
对于您的计划,您必须决定是否需要deck
和hand
是多态的。
如果是,请在堆上创建它们(使用new
),存储并通过指针传递它们,并且当你完成它们时不要忘记再次删除它们(或者看看它们)智能指针)。
如果不是,请给它们关系运算符(bool operator==(const deck &lhs, const deck &rhs)
,...),复制语义(deck(const deck&)
,deck &operator=(const deck&)
),在堆栈上创建它们并按值存储它们。通过(const)引用传递它们。您不需要删除它们,编译器会为您执行此操作。