The C++Course provides a general introduction to programming in C++. It is based on A.B. Downey's book, How to Think Like a Computer Scientist. Click here for details.


The Printcard Function

When you create a new type, the first step is usually to declare the instance variables and write constructors. The second step is often to write a function that prints the object in human-readable form.

In the case of Card objects, "human-readable" means that we have to map the internal representation of the rank and suit onto words. A natural way to do that is with a vector of pstrings. You can create a vector of pstrings the same way you create an vector of other types:

  pvector<pstring> suits (4);

Of course, in order to use pvectors and pstrings, you will have to include the header files for both.

pvectors are a little different from pstrings in this regard. The file pvector.cpp contains a template that allows the compiler to create vectors of various kinds. The first time you use a vector of integers, the compiler generates code to support that kind of vector. If you use a vector of pstrings, the compiler generates different code to handle that kind of vector. As a result, it is usually sufficient to include the header file pvector.h; you do not have to compile pvector.cpp at all! Unfortunately, if you do, you are likely to get a long stream of error messages. I hope this helps you avoid an unpleasant surprise, but the details in your development environment may differ.

To initialize the elements of the vector, we can use a series of assignment statements.

  suits[0] = "Clubs";
  suits[1] = "Diamonds";
  suits[2] = "Hearts";
  suits[3] = "Spades";

A state diagram for this vector looks like this:

We can build a similar vector to decode the ranks. Then we can select the appropriate elements using the suit and rank as indices. Finally, we can write a function called print that outputs the card on which it is invoked:

void Card::print () const
{
  pvector<pstring> suits (4);
  suits[0] = "Clubs";
  suits[1] = "Diamonds";
  suits[2] = "Hearts";
  suits[3] = "Spades";

  pvector<pstring> ranks (14);
  ranks[1] = "Ace";
  ranks[2] = "2";
  ranks[3] = "3";
  ranks[4] = "4";
  ranks[5] = "5";
  ranks[6] = "6";
  ranks[7] = "7";
  ranks[8] = "8";
  ranks[9] = "9";
  ranks[10] = "10";
  ranks[11] = "Jack";
  ranks[12] = "Queen";
  ranks[13] = "King";

  cout << ranks[rank] << " of " << suits[suit] << endl;
}

The expression suits[suit] means "use the instance variable suit from the current object as an index into the vector named suits, and select the appropriate string."

Because print is a Card member function, it can refer to the instance variables of the current object implicitly (without having to use dot notation to specify the object). The output of this code

  Card card (1, 11);
  card.print ();

is Jack of Diamonds.

You might notice that we are not using the zeroeth element of the ranks vector. That's because the only valid ranks are 1--13. By leaving an unused element at the beginning of the vector, we get an encoding where 2 maps to "2", 3 maps to "3", etc. From the point of view of the user, it doesn't matter what the encoding is, since all input and output uses human-readable formats. On the other hand, it is often helpful for the programmer if the mappings are easy to remember.


Last Update: 2005-12-05