简体   繁体   English

C ++二十一点功能

[英]C++ Blackjack Function

I've started teaching myself C++ and have been trying to write a blackjack program. 我已经开始自学C ++,并一直在尝试编写二十一点程序。 I'm trying to use classes to represent the cards, deck, and hands. 我正在尝试使用类来表示纸牌,副牌和手牌。 I believe everything is working in the program so far except the dealCardToHand() method. 我相信到目前为止,除dealCardToHand()方法外, dealCardToHand()所有程序都在程序中dealCardToHand()

void dealCardToHand(deck& d, hand& h){
    h.setCard(h.getCardsInHand(), d.dealCard());
    h.setCardsInHand(h.getCardsInHand() + 1);
}

It seems to correctly increment the number of cards in the hand but does not call the setCard() method with the correct data. 似乎可以正确地增加手中的牌数,但不会使用正确的数据调用setCard()方法。 Any help would be appreciated. 任何帮助,将不胜感激。 I'm including the relevant classes and methods: 我包括了相关的类和方法:

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();
};

This is dangerous (and probably at least part of your problem): 这很危险(可能至少是问题的一部分):

void setCard(int i, card c) {handCards[i]=&c;}

Here, setCard(...) is passed a card object by value. 在这里, setCard(...)按值传递了一个card对象。 This means that a new copy of the caller's card is created in temporary location. 这意味着将在临时位置创建呼叫者card的新副本。 It is this copy ( c ) which setCard() acts on. setCard()作用于此副本( c )。 By setting handCards[i]=&c; 通过设置handCards[i]=&c; , you save the location of this temporary object. ,您将保存该临时对象的位置。 But when setCard() returns, that temporary object is no longer valid. 但是当setCard()返回时,该临时对象不再有效。

But then you go on to dereference handCards[i] in getCard() . 但是随后您继续在getCard()取消引用handCards[i] This yields undefined behavior. 这会产生不确定的行为。 In theory, you should expect demons to start flying out of your nose. 从理论上讲,您应该期望恶魔开始从您的鼻子中飞出来。 In practice, you will see total garbage returned from getCard() . 在实践中,您将看到从getCard()返回的总垃圾。 Or a crash. 还是崩溃。 Or maybe, if you're sufficiently unlucky, the last value passed into setCard() . 或者,如果您不够幸运,则将最后一个值传递给setCard()

On the whole, it looks like you're playing fast and loose with pointers. 总的来说,您似乎在玩指针时快而松。 I'd suggest one of two ways to resolve the problem: 我建议采用以下两种解决方法之一:

  1. Use pointers everywhere, never pass or return by value. 随处使用指针,永远不要传递或返回值。 This will probably lead to other issues, but they might not be quite so mysterious. 这可能会导致其他问题,但是它们可能并不是那么神秘。
  2. Use pointers nowhere. 无处使用指针。 Pass and return everything by value. 传递并按值返回一切。

Of course those aren't the only options, but they might make your life easier for the time being. 当然,这些并不是唯一的选择,但是暂时可以使您的生活更轻松。

As others have noted, the issue is that you're storing the address of a temporary variable in a pointer variable and dereference that pointer variable after the temporary has gone out of scope (and has been deleted). 正如其他人指出的那样,问题是您将临时变量的地址存储在指针变量中,并在临时变量超出范围(并已删除)之后取消引用该指针变量。

Allow my answer to move a bit more into the abstract: 让我的答案更多地进入摘要:

In C++, we distinguish between value classes and polymorphic classes. 在C ++中,我们区分值类和多态类。 You will find them under different names, and you will also find classes where the distinction between the two is not as sharp as one would like, but it roughly goes like this: 您会发现它们使用不同的名称,并且还会找到这样的类,它们之间的区别并不像人们希望的那样尖锐,但大致是这样的:

  1. Value class instances differ from each other in their state. 值类实例的状态彼此不同。 If the state of two instances is equal, the behaviour of the instances will be equal, too. 如果两个实例的状态相等,则实例的行为也将相等。

    Examples of value classes are std::string , all STL containers, std::complex<> , etc. 值类的示例为std::string ,所有STL容器, std::complex<>等。

    You use them as you would use int s: you create them on the stack: 您可以像使用int一样使用它们:在堆栈上创建它们:

     std::string s = "Hello, World"; // NOT std::string * s = new std::string; 

    aggregate them by value: 按价值汇总:

     class Widget { std::complex<double> m_value; // NOT std::complex<double> * m_value; public: // ... }; 

    you can usually compare them for equality, copy them around, store them in containers: 您通常可以比较它们是否相等,复制它们或将它们存储在容器中:

     std::vector<std::string> vec; std::string s = "Hello, World"; assert( s == "Hello, World" ); vec.push_back( s ); 

    and, most relevant to your question, you pass them around by (const-)reference (or by value, esp. if they're very small), and you return them by value, too: 并且,与您的问题最相关的是,您按(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 
  2. Polymorphic classes differ in behaviour, not state. 多态类的行为有所不同,而不是状态。 Two instances of a polymorphic class may have the same state, yet still behave completely different. 一个多态类的两个实例可能具有相同的状态,但仍然表现出完全不同的状态。 Polymorphic classes may also differ in their state, but the focus is on their behaviour. 多态类的状态也可能有所不同,但是重点在于它们的行为。 This is what OOP (object-oriented programming) is all about. 这就是OOP(面向对象编程)的全部目的。

    Borrowing example classes from the well-known C++ library "Qt", a QLineEdit and a QPushButton are both QWidget s. 从著名的C ++库“ Qt”, QLineEditQPushButton借用的示例类都是QWidget They may have the same state (size, position, ...), yet what happens when you click into each with the mouse is completely different between them. 它们可能具有相同的状态(大小,位置等),但是当您用鼠标单击每个状态时,它们之间会发生完全不同的情况。

    In C++, to use polymorphic behaviour, you must call virtual functions, and you must do so through a pointer or reference to a common base class ( QWidget in the above). 在C ++中,要使用多态行为,必须调用函数,并且必须通过指针或对通用基类(上述QWidget )的引用来实现。 Therefore, polymorphic classes are usually allocated on the heap: 因此,多态类通常在堆上分配:

     QLineEdit * le = new QLineEdit(); QPushButton * pb = new QPushButton(); QWidget * leAsWidget = le; // works QWidget * pbAsWidget = pb; // works 

    and stored and passed around in (smart) pointer variables: 并在(智能)指针变量中存储和传递:

     class MyWidget : public QWidget { QLineEdit * m_lineEdit; QPointer<QPushButton> m_pushButton; // QPointer is a smart pointer public: // ... }; 

For your program, you have to decide whether you need deck and hand to be polymorphic or not. 对于您的程序,您必须决定是否需要deckhand是多态的。

If yes, create them on the heap (with new ), store and pass them around by pointer, and don't forget to delete them again when you're done with them (or have a look at smart pointer). 如果是,请在堆上创建它们(使用new ),通过指针进行存储并传递它们,并且别忘了在使用完它们后再次删除它们(或查看智能指针)。

If no, give them relational operators ( bool operator==(const deck &lhs, const deck &rhs) , ...), copy semantics ( deck(const deck&) , deck &operator=(const deck&) ), create them on the stack and store them by value. 如果否,请给他们关系运算符( bool operator==(const deck &lhs, const deck &rhs) ,...),复制语义( deck(const deck&)deck &operator=(const deck&) ),在堆栈上创建它们并按值存储它们。 Pass them around by (const) reference. 通过(const)参考传递它们。 You don't need to delete them, the compiler will do that for you. 您不需要删除它们,编译器会为您完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM