2

私は独学で 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();
};
4

2 に答える 2

4

これは危険です(そしておそらくあなたの問題の少なくとも一部です):

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

ここでは、値によってオブジェクトsetCard(...)が渡されます。cardこれは、呼び出し元の新しいコピーがcard一時的な場所に作成されることを意味します。作用するのはこのコピー ( c)です。setCard()を設定するhandCards[i]=&c;と、この一時オブジェクトの場所が保存されます。しかし、setCard()戻ると、その一時オブジェクトは無効になります。

handCards[i]しかし、その後で逆参照に進みますgetCard()。これにより、未定義の動作が発生します。理論的には、悪魔が鼻から飛び出し始めると予想する必要があります。実際には、 から返されたガベージの合計が表示されgetCard()ます。またはクラッシュ。または、十分に運が悪い場合は、最後に渡された値がsetCard().

全体として、ポインタを使って速くてルーズにプレイしているように見えます。問題を解決するには、次の 2 つの方法のいずれかをお勧めします。

  1. どこでもポインタを使用し、決して値渡しや戻りを行わないでください。これはおそらく他の問題につながる可能性がありますが、それほど不可解ではないかもしれません.
  2. どこにもポインターを使用しないでください。すべてを値で渡し、返します。

もちろん、これらが唯一の選択肢ではありませんが、当面はあなたの生活を楽にしてくれるかもしれません.

于 2012-06-21T04:38:06.410 に答える
0

他の人が指摘したように、問題は、一時変数のアドレスをポインター変数に格納し、一時変数がスコープ外になった (および削除された) 後にそのポインター変数を逆参照することです。

私の答えをもう少し抽象化してみましょう:

C++ では、値クラスとポリモーフィック クラスを区別します。それらは異なる名前で見つかります。また、2 つの間の区別が希望するほど明確ではないクラスも見つかりますが、大まかに次のようになります。

  1. 値クラスのインスタンスは、状態が互いに異なります。2 つのインスタンスの状態が等しい場合、インスタンスの動作も等しくなります。

    値クラスの例はstd::string、 、すべての STL コンテナーstd::complex<>などです。

    sを使用するのと同じように使用し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
    
  2. ポリモーフィック クラスは、状態ではなく動作が異なります。ポリモーフィック クラスの 2 つのインスタンスは、同じ状態であっても、まったく異なる動作をする場合があります。ポリモーフィック クラス状態が異なる場合がありますが、焦点はその動作にあります。これが、OOP (オブジェクト指向プログラミング) のすべてです。

    有名な C++ ライブラリ「Qt」からサンプル クラスを借りると、aQLineEditと aQPushButtonは両方ともQWidgets です。それらは同じ状態 (サイズ、位置など) を持っているかもしれませんが、マウスでそれぞれをクリックしたときに何が起こるかは、それらの間で完全に異なります。

    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) 参照によってそれらを渡します。それらを削除する必要はありません。コンパイラが削除してくれます。

于 2012-06-21T20:34:48.837 に答える