We’ve seen how an object can contain an array. We can also reverse that situation and create an arrays of objects. We’ll look at two situations: an array of English distances and a deck of cards.
Arrays of English Distances
“Objects and Classes,” we showed several examples of an English Distance class that incorporated feet and inches into an object representing a new data type. The next program, ENGLARAY, demonstrates an array of such objects.
// englaray.cpp // objects using English measurements #include <iostream> using namespace std; //////////////////////////////////////////////////////////////// class Distance //English Distance class { private: int feet; float inches; public: void getdist() //get length from user { cout << “\n Enter feet: “; cin >> feet; cout << “ Enter inches: “; cin >> inches; } void showdist() const //display distance { cout << feet << “\’-” << inches << ‘\”’; } }; //////////////////////////////////////////////////////////////// int main() { Distance dist[100]; //array of distances int n=0; //count the entries char ans; //user response (‘y’ or ‘n’) cout << endl; do { //get distances from user cout << “Enter distance number “ << n+1; dist[n++].getdist(); //store distance in array cout << “Enter another (y/n)?: “; cin >> ans; } while( ans != ‘n’ ); //quit if user types ‘n’ for(int j=0; j<n; j++) //display all distances { cout << “\nDistance number “ << j+1 << “ is “; dist[j].showdist(); } cout << endl; return 0; }
In this program the user types in as many distances as desired. After each distance is entered, the program asks if the user desires to enter another. If not, it terminates, and displays all the distances entered so far. Here’s a sample interaction when the user enters three distances:
Enter distance number 1
Enter feet: 5
Enter inches: 4
Enter another (y/n)? y
Enter distance number 2
Enter feet: 6
Enter inches: 2.5
Enter another (y/n)? y
Enter distance number 3
Enter feet: 5
Enter inches: 10.75
Enter another (y/n)? n
Distance number 1 is 5’-4”
Distance number 2 is 6’-2.5”
Distance number 3 is 5’-10.75”
Of course, instead of simply displaying the distances already entered, the program could have averaged them, written them to disk, or operated on them in other ways.
Array Bounds
This program uses a do loop to get input from the user. This way the user can input data for as many structures of type part as seems desirable, up to MAX, the size of the array (which is set to 100).
Although it’s hard to imagine anyone having the patience, what would happen if the user entered more than 100 distances? The answer is, something unpredictable but almost certainly bad. There is no bounds checking in C++ arrays. If the program inserts something beyond the end of the array, neither the compiler nor the runtime system will object. However, the renegade data will probably be written on top of other data or the program code itself. This may cause bizarre effects or crash the system completely.
if( n >= MAX )
{
cout << “\nThe array is full!!!”;
break;
}
This causes a break out of the loop and prevents the array from overflowing.
Accessing Objects in an Array
The declaration of the Distance class in this program is similar to that used in previous programs. However, in the main() program we define an array of such objects:
Distance dist[MAX];
Here the data type of the dist array is Distance, and it has MAX elements. Figure shows what this looks like.
A class member function that is an array element is accessed similarly to a structure member that is an array element, as in the PARTARAY example. Here’s how the showdist() member function of the jth element of the array dist is invoked:
dist[j].showdist();
As you can see, a member function of an object that is an array element is accessed using the dot operator: The array name followed by the index in brackets is joined, using the dot operator, to the member function name followed by parentheses. This is similar to accessing a structure (or class) data member, except that the function name and parentheses are used instead of the data name.
Notice that when we call the getdist() member function to put a distance into the array, we take the opportunity to increment the array index n:
dist[n++].getdist();
This way the next group of data obtained from the user will be placed in the structure in the next array element in dist. The n variable must be incremented manually like this because we use a do loop instead of a for loop. In the for loop, the loop variable which is incremented automatically can serve as the array index.
Arrays of Cards
Here’s another, somewhat longer, example of an arrays of objects. You will no doubt remember the CARDOBJ example from Chapter 6. We’ll borrow the card class from that example, and group an array of 52 such objects together in an array, thus creating a deck of cards. Here’s the listing for CARDARAY:
// cardaray.cpp // cards as objects #include <iostream> #include <cstdlib> //for srand(), rand() #include <ctime> //for time for srand() using namespace std; enum Suit { clubs, diamonds, hearts, spades }; //from 2 to 10 are integers without names const int jack = 11; const int queen = 12; const int king = 13; const int ace = 14; //////////////////////////////////////////////////////////////// class card { private: int number; //2 to 10, jack, queen, king, ace Suit suit; //clubs, diamonds, hearts, spades public: card() //constructor { } void set(int n, Suit s) //set card { suit = s; number = n; } void display(); //display card }; //-------------------------------------------------------------- void card::display() //display the card { if( number >= 2 && number <= 10 ) cout << number; else switch(number) { case jack: cout << “J”; break; case queen: cout << “Q”; break; case king: cout << “K”; break; case ace: cout << “A”; break; } switch(suit) { case clubs: cout << static_cast(5); break; case diamonds: cout << static_cast(4); break; case hearts: cout << static_cast(3); break; case spades: cout << static_cast(6); break; } } //////////////////////////////////////////////////////////////// int main() { card deck[52]; int j; cout << endl; for(j=0; j<52; j++) //make an ordered deck { int num = (j % 13) + 2; //cycles through 2 to 14, 4 times Suit su = Suit(j / 13); //cycles through 0 to 3, 13 times deck[j].set(num, su); //set card } cout << “\nOrdered deck:\n”; for(j=0; j<52; j++) //display ordered deck { deck[j].display(); cout << “ “; if( !( (j+1) % 13) ) //newline every 13 cards cout << endl; } srand( time(NULL) ); //seed random numbers with time for(j=0; j<52; j++) //for each card in the deck, { int k = rand() % 52; //pick another card at random card temp = deck[j]; //and swap them deck[j] = deck[k]; deck[k] = temp; } cout << “\nShuffled deck:\n”; for(j=0; j<52; j++) //display shuffled deck { deck[j].display(); cout << “, “; if( !( (j+1) % 13) ) //newline every 13 cards cout << endl; } return 0; } //end main
Once we’ve created a deck, it’s hard to resist the temptation to shuffle it. We display the cards in the deck, shuffle it, and then display it again. To conserve space we use graphics characters for the club, diamond, heart, and spade. Figure shows the output from the program. This program incorporates several new ideas, so let’s look at them in turn.
Graphics Characters
There are several special graphics characters in the range below ASCII code 32. (See Appendix A, “ASCII Table,” for a list of ASCII codes.) In the display() member function of card we use codes 5, 4, 3, and 6 to access the characters for a club, a diamond, a heart, and a spade, respectively. Casting these numbers to type char, as in static_cast(5)
causes the << operator to print them as characters rather than as numbers.
The Card Deck
The array of structures that constitutes the deck of cards is defined in the statement card deck[52]; which creates an array called deck, consisting of 52 objects of type card. To display the jth card in the deck, we call the display() member function: deck[j].display();
Random Numbers
It’s always fun and sometimes even useful to generate random numbers. In this program we use them to shuffle the deck. Two steps are necessary to obtain random numbers. First the random number generator must be seeded, or initialized. To do this we call the srand() library function. This function uses the system time as the seed, so it requires two header files, CSTDLIB and CTIME.
To actually generate a random number we call the rand() library function. This function returns a random integer. To get a number in the range from 0 to 51, we apply the remainder operator and 52 to the result of rand().
int k = rand() % 52;
The resulting random number k is then used as an index to swap two cards. We go through the for loop, swapping one card, whose index points to each card in 0-to-51 order, with another card, whose index is the random number. When all 52 cards have been exchanged with a random card, the deck is considered to be shuffled. This program could form the basis for a card playing program, but we’ll leave these details for you.
Arrays of objects are widely used in C++ programming. We’ll see other examples as we go along.
Read More Topics |
Arrays in C language |
Array structures and unions in C |
Arrays programming |