13.5. card_deck member functions

Now that we have a card_deck object, it makes sense to put all the functions that pertain to card_decks in the card_deck structure definition. Looking at the functions we have written so far, one obvious candidate is print_deck (Section 12.7). Here’s how it looks, rewritten as a card_deck member function:

void card_deck::print () const {
  for (std::size_t i = 0; i < cards.size(); i++) {
    cards[i].print ();
  }
}

As usual, we can refer to the instance variables of the current object without using dot notation.

The active code below prints out the deck of cards like in the previous section. Notice we can just use deck.print () to print out the deck instead of writing a for loop in main.

Example c192_deck_members_ac_1
 1#include <cstddef>
 2#include <iostream>
 3#include <string>
 4#include <vector>
 5
 6enum card_suit { clubs, diamonds, hearts, spades };
 7
 8enum card_rank { ace=1, two, three, four, five, six, seven, eight, nine,
 9ten, jack, queen, king };
10
11struct playing_card {
12    card_rank rank;
13    card_suit suit;
14    playing_card ();
15    playing_card (card_suit s, card_rank r);
16    void print () const;
17};
18
19struct card_deck {
20    std::vector<playing_card> cards;
21    card_deck ();
22   void print () const;
23};
24
25int main() {
26    card_deck deck;
27    deck.print ();
28}

For some of the other functions, it is not obvious whether they should be member functions of playing_card, member functions of card_deck, or nonmember functions that take playing_cards and card_decks as parameters. For example, the version of find in the previous chapter takes a playing_card and a card_deck as arguments, but you could reasonably make it a member function of either type. As an exercise, rewrite find as a card_deck member function that takes a playing_card as a parameter.

Writing find as a playing_card member function is a little tricky. Here’s my version:

std::ptrdiff_t playing_card::find (const card_deck& deck) const {
  for (std::size_t i = 0; i < deck.cards.size(); i++) {
    if (equals (deck.cards[i], *this)) return static_cast<std::ptrdiff_t>(i);
  }
  return -1;
}

The first trick is that we have to use the keyword this to refer to the playing_card the function is invoked on.

The second trick is that C++ does not make it easy to write structure definitions that refer to each other. The problem is that when the compiler is reading the first structure definition, it doesn’t know about the second one yet.

One solution is to declare card_deck before playing_card and then define card_deck afterwards:

// declare that card_deck is a structure, without defining it
struct card_deck;

// that way we can refer to it in the definition of playing_card
struct playing_card {
  int suit, rank;

  playing_card ();
  playing_card (int s, int r);

  void print () const;
  bool is_greater (const playing_card& c2) const;
  std::ptrdiff_t find (const card_deck& deck) const;
};

// and then later we provide the definition of card_deck
struct card_deck {
  std::vector<playing_card> cards;

  card_deck ();
  card_deck (std::size_t n);
  void print () const;
  std::ptrdiff_t find (const playing_card& card) const;
};

Multiple Response: What are some tricks we can use to write find as a Card member function?

Write find as a card_deck member function that takes a playing_card as a parameter.

  1.    }
       return -1;
    }
  2. for (std::size_t i = 0; i < cards.size(); i++) {
  3. for (std::size_t i = 0; i < deck.cards.size(); i++) {
  4. if (cards[i].equals(card)) {
       return static_cast<std::ptrdiff_t>(i);
    }
  5. if (equals (deck.cards[i], *this)) {
       return static_cast<std::ptrdiff_t>(i);
    }
  6. std::ptrdiff_t card_deck::find (playing_card card) const {
  7. std::ptrdiff_t find (playing_card) {

The active code below uses the find function that we just wrote.

Example c192_deck_members_ac_2
 1#include <cstddef>
 2#include <iostream>
 3#include <string>
 4#include <vector>
 5
 6enum card_suit { clubs, diamonds, hearts, spades };
 7
 8enum card_rank { ace=1, two, three, four, five, six, seven, eight, nine,
 9ten, jack, queen, king };
10
11struct playing_card {
12    card_rank rank;
13    card_suit suit;
14    playing_card ();
15    playing_card (card_suit s, card_rank r);
16    void print () const;
17    bool equals (const playing_card& c2) const;
18};
19
20struct card_deck {
21    std::vector<playing_card> cards;
22    card_deck ();
23    void print () const;
24    std::ptrdiff_t find (playing_card card) const;
25};
26
27int main() {
28    card_deck deck;
29    playing_card card (clubs, ace);
30    playing_card card2 (diamonds, ace);
31    // Should output 0 and 13
32    std::cout << deck.find(card) << std::endl;
33    std::cout << deck.find(card2) << std::endl;
34}