Section 5 - A Character Counter Class

8B.5.1 Classes Using Other Classes

Now that we have our Frequency class, we can use it inside another class, CharacterCounter, that we are going to build.  CharacterCounter is going to do almost everything for us, and the main() method won't need to even know about the Frequency class. 

CharacterCounter will have two members:

class CharacterCounter
{
private:
Frequency letters;
string userString;

// ... methods for class ...

}

In our client, we will get a string from the user and use it to instantiate a CharacterCounter object.

int main()
{
string userPhrase;

cout << "Enter a phrase or sentence: " << endl;
getline(cin, userPhrase);

// create a CharacterCounter object for this phrase
CharacterCounter freq(userPhrase);

// ...

All of the counting is done inside the CharacterCounter constructor so by the time we finish instantiating this object, we are done!  All we have to do is print out the results.  We will give CharacterCounter an accessor method, getCount(), that will return the count of individual letters.  Here is how main will print out the results:

// display whole table
for (char let = 'A'; let <= 'Z'; let++)
{
// every 5 items, generate a newline
if ( (let - 'A') % 5 == 0)
cout << endl;

cout << let << ": " << freq.getCount(let) << "     ";
}

Because I can design this class any way I want, I'm going to allow getCount() to take the chars 'A' through 'Z' and convert to the numbers 0 through 25 inside the class.   You can see this by looking up and noticing that we are passing let, which holds the value of a letter, directly to getCount().  Here is a sample run:

console shot

8B.5.2 The Program Listing

Here is the entire listing in one place.  Three classes.  Try it out.  Can you find an improvement that would enable main() to ignore completely the details of printing out the table?  That would be a good modification for you to make.

#include <string>
#include <iostream>
using namespace std;

// 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);
};
// end of class Frequency prototype --------------

// class CharacterCounterprototype -----------------------
class CharacterCounter
{
private:
Frequency letters;
string userString;

public:
CharacterCounter(string str);
long getCount(char let);
private:
void countOccurrences();

};
// end of CharacterCounter method definitions  --------------

int main()
{
string userPhrase;

cout << "Enter a phrase or sentence: " << endl;
getline(cin, userPhrase);

// create a CharacterCounter object for this phrase
CharacterCounter freq(userPhrase);

// display whole table
for (char let = 'A'; let <= 'Z'; let++)
{
// every 5 items, generate a newline
if ( (let - 'A') % 5 == 0)
cout << endl;

cout << let << ": " << freq.getCount(let) << "     ";
}
}

// 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  --------------

// beginning of CharacterCounter  method definitions -------------
CharacterCounter::CharacterCounter(string str)
{
// if string is not good, use empty string
if (str.length() >= 1 )
userString = str;
else
userString = "";
countOccurrences();
}

void CharacterCounter::countOccurrences()
{
char let;
int k;

// letters[] automatically initialized to all 0s
// scan the string and increment as we go
for (k = 0; k < userString.length(); k++)
{
let = toupper(userString[k]);
letters.increment( let - 'A' );  // note cute conversion
}
}

long CharacterCounter::getCount(char let)
{
char up_let;
up_let = toupper(let);
return letters.get(up_let - 'A');
}
// end of CharacterCounter method definitions  --------------

And, that should do it for this module.