Arrays of Objects, Composition Example with arrays

Arrays of objects:

In addition to building arrays of built-in types, we can have arrays of objects.
 Fraction rationals[20];  // array of 20 Fraction objects 
 Complex nums[50];        // an array of 50 Complex objects
 Hydrant fireplugs[10];   // an array of 10 objects of type Hydrant (a dog's dream!)

In an array of objects, each array position is a single object. So, after the above declaration of the "rationals" array, there are 20 Fraction objects, named rationals[0], rationals[1], ... , rationals[19].

Initializing

What about initializing arrays of objects? Normally the constructor initializes an object. If an class has a default constructor (i.e. no parameters), then the default constructor will be the one that runs for the objects in the array, unless you specify otherwise.

 
  Fraction numList[4];       // builds 4 fractions using default constructor

To specify different constructors to be used for different objects in the array, you can use an initializer on the declaration (the set notation format used with basic types), but instead of values, you actually list the constructor calls to be used (this is one of the very few places where a constructor will seem to be explicitly called):

  Fraction numList[3] = { Fraction(2,4) , Fraction(5) , Fraction() }; 
  // this allocates an array of 3 fractions, initialized to 2/4,  5/1,  and 0/1

Using arrays of objects

In usage of these objects, the dot-operator works the same as with single names:

Format:  objectName.memberName

  Fraction rationals[20]; // create an array of 20 Fraction objects
  ...
  rationals[2].Show();    // displays the third Fraction object 
  rationals[6].Input();   // calls Input function for the 7th Fraction 
  cout << rationals[18].Evaluate(); 

Card game example:

This example program is a Blackjack card game simulation. There are several classes involved, and the composition relationship is used extensively. This includes the embedding of arrays of objects. For example, the Deck class contains an array of 52 Card objects inside. The following is a portion of the declaration of the Deck class, which illustrates this use of composition ("has-a" relationship):
 class Deck 
 {  
 public: 
     ....		// member functions
 private: 
     int topCard;       // points to position of current top card of deck 
     Card cards[52];    // a deck is 52 cards. 
 }; 

A useful techniqe used here is the extra topCard variable. While this is not data that the user of the class is specifically interested in, this variable is an extra tracking variable used internally to store the index of the next card to be dealt. This allows us to deal cards without having to shift card positions in the array. When a card is dealt, we simply increment topCard to the next index position. When topCard is 52, we've dealt the whole deck.

Here is a portion of the Player class:

 class Player 
 { 
 public: 
     ....		  // member functions
 private: 
     Card hand[5]; 
     int numCards;        // the number of cards currently in the hand 
     int HandValue();     // calculates the numeric value of the hand 
     void ShowHand();     // displays a player's hand and value 
 }; 

This class uses another similar tracking variable technique, but one that is much more common with arrays. The array called hand can store up to 5 objects of type Card.  However, a Blackjack hand only starts with 2 cards!  This means that the array is not always full.  We do not always use 5 slots.  How do we track this? How do we ensure that the other allocated slots are viewed as being empty (we cannot physically empty them, because memory always has some sequence of bits).

The variable numCards, in this situation, is used to store the number of cards actually in the Player's hand at any given time.  If we have two cards, numCards is 2.  If we are dealt another card, numCards is incremented to 3.  numCards serves a dual purpose here:  It not only tells us how many cards are in the hand (i.e. how many array slots are being used), but it also stores the next available index in the array!  If numCards is 2, then index positions 0 and 1 are filled, and 2 is the next available.

Example of numCards being used in a function:

 for (int i = 0; i < numCards; i++) 
     hand[i].Display();                // only displays the filled card slots