Section 4 - Arrays Inside Classes
8B.4.1 Arrays Out of Bounds
We want to count the number of occurrences of the letters 'A' through 'Z' in a string that the user types. We might use an array of longs that has 26 elements. elem[0] would hold the count of 'A's, elem[1] the count of 'B's, ... and elem[25] the count of 'Z's.
However arrays create a big headache for us. Look:
long badFreq[26]; badFreq[-7] = 10; badFreq[50] = 1; badFreq[5] = -3;
The first two are out-of-bounds of the array. We can only access elements 0 through 25. The third is legal, technically, but makes no sense, since negative numbers can never be frequencies.
We can fix all of this by creating a class called Frequency which wraps around the array of longs and protects against all of this ugliness.
8B.4.2 A Robust Array: Frequency
We wrap our array of longs in a new class called Frequency. Since we want Frequency to be flexible, we won't restrict it to 26 elements, but allow the number of elements to be set during instantiation by the constructor.
// class Frequency prototype ----------------------- class Frequency { private: static const int MAX_SIZE = 100000; int count[MAX_SIZE]; int size; public: Frequency(int size = 26); int get(int index); void increment(int index); void decrement(int index); }; // beginning of Frequency method definitions ------------- Frequency::Frequency(int size) { if (size <= 0 || size > MAX_SIZE) size = MAX_SIZE; this->size = size; for (int k=0; k < size; k++) count[k] = 0; } int Frequency::get(int index) { if (index >= 0 && index < size) return count[index]; else return -1; } void Frequency::increment(int index) { if (index >= 0 && index < size) count[index]++; } void Frequency::decrement(int index) { if (index >= 0 && index < size) if (count[index] > 0) count[index]--; } // end of Frequency method definitions --------------
This class provides methods for incrementing and decrementing the individual elements of the array, and also an accessor to return any value in the array.
It provides the following protections:
- No direct public access to the frequency counts.
- No attempts to increment or decrement an index outside the bounds of the array.
- No accidental decrements below 0, since counts below 0 have no meaning.
Here is a nice use of this class:
int main() { int k; Frequency letters(26); // this block should leave a 27 in letter[2] for (k = 0; k < 28; k++) letters.increment(2); letters.decrement(2); // this block should leave a 59 in letter[25] for (k = 0; k < 59; k++) letters.increment('Z' - 'A'); // this is 25 // some illegal accesses letters.decrement(500); letters.increment(-3); // display whole table, going "too far" for (k = -3; k < 30; k++) { // every 5 items, generate a newline if ( k % 5 == 0) cout << endl; cout << k << ": " << letters.get(k) << " "; } cout << endl; }
This gives us the following console output:

First, we explain the interesting notation in the constructor prototype:
public: Frequency(int size = 26);
The " = 26" means that we can omit an argument when we call the constructor and, if we do, the value 26 will be substituted. It is like a default parameter and in fact is called just that " a default parameter."
As you can see, the value -1 is sent back to the client indicating a bad index access. Our Frequency class is robust and handles the errors with alacrity.
Also, notice that we are using char notation as a more readable option to access the elements. Instead of trying to figure out what index the letter 'R' refers to, we use the numeric expression 'R' - 'A', which automatically converts the 'R' ASCII code to the proper index. Obviously, 'A' - 'A' becomes 0, as it should, 'B' - 'A' becomes 1, etc. So, instead of passing integer indexes directly, we will take a char, letter, and form the index using the expression letter - 'A'.
We are only going to have to deal with capital letters (upper case) in our program, as you will see.