Chapter 19

Programming with Class

In This Chapter

arrow Grouping data using parallel arrays

arrow Grouping data in a class

arrow Declaring an object

arrow Creating arrays of objects

Arrays are great at handling sequences of objects of the same type, such as ints or doubles. Arrays do not work well, however, when grouping different types of data — as when we try to combine a Social Security number with the name of a person into a single record. C++ provides a structure called the class (or struct) to handle this problem.

Grouping Data

Many of the programs in earlier chapters read a series of numbers, sometimes into an array, before processing. A simple array is great for standalone values. However, many times (if not most of the time), data comes in groups of information. For example, a program may ask the user for his first name, last name, and Social Security number. Alone, any one of these values is not sufficient — only in the aggregate do the values make any sense.

You can store associated data of different types in what are known as parallel arrays. For example, I might use an array of strings called pszFirstNames to hold people’s first names, a second pszLastNames to hold the last names, and a third nSocialSecurities to hold the corresponding Social Security number. I would store the data such that any given index n points to the data for a given individual.

Thus my personal data might be at offset 3. In that case, szFirstNames[3] would point to “Stephen,” szLastNames[3] would point to “Davis,” and nSocialSecurityNumbers[3] would contain … well, you get the idea. This is shown in Figure 19-1.

9781118823873-fg1901.tif

Figure 19-1: Parallel arrays are sometimes used to hold collections of related-but-dissimilar data in languages that don’t support classes.

This method works, but it’s prone to errors because there’s nothing that directly associates the first name with the last name and the Social Security number other than an index. You could easily imagine that a missing instruction here or there, and I would become “Stephen Eddins” or any other random combination of first and last names.

Fortunately for us, C++ provides a better way.

The Class

A first name or a Social Security number doesn’t make any sense except in the context of the person to whom they belong — data like that must have a context created by association with other, related data. What we would like is to be able to create a structure, say Person, that contains all of the relevant properties that make up a person (in this case, first name, last name, and Social Security number).

C++ uses a structure known as the class that has the following format:

  class Person
{
  public:
    char szFirstName[128];
    char szLastName[128];
    int  nSocialSecurityNumber;
};

A class definition starts with the keyword class followed by the name of the class and an open brace.

tip.eps The naming rules for class names are the same as for variable names: The first letter must be one of the letters ‘a’ through ‘z’ or ‘A’ through ‘Z’ or underscore. Every subsequent character in the name must be one of these or the digits ‘0’ through ‘9’. By convention, class names always start with an uppercase letter. Class names normally consist of multiple words jammed together, with each word starting with an uppercase letter.

The first keyword within the open brace in the early examples will always be public. (I describe the alternatives to public in Chapter 24; for the moment, just accept it as part of the declaration.)

tip.eps You can also use the keyword struct instead of class. A struct is identical to a class in every respect except that the public is assumed in a struct. For historical reasons, the term class is more popular in C++; the term struct is used more often in C programs.

Following the public keyword are the declarations for the entries it takes to describe the class. The Person class contains two arrays for the first and last names and a third entry to hold the Social Security number.

remember.eps The entries within a class are known as members or properties of the class.

The Object

Declaring a class in C++ is like defining a new variable type. You can create a new instance of a class as follows:

  Person me;

An instance of a class is called an object.

tip.eps People get confused about the difference between a class and an object; sometimes people even use the terms interchangeably. Actually, the difference is easy to explain with an example. Dog is a class. My dog, Lollie, is an instance of a dog. My other dog, Jack, is a separate, independent instance of a dog. Dog is a class; lollie and jack are objects.

You can access the members of an object by including their name after the name of the object followed by a dot, as in the following:

  Person me;
me.nSocialSecurityNumber = 456789012;
cin >> me.szLastName;

Here me is an object of class Person. The element me.nSocialSecurityNumber is a member or property of the me object. The type of me is Person. The type of me.nSocialSecurityNumber is int, and its value is set to 456-78-9012. The type of me.szLastName is char[] (pronounced “array of char”).

A class object can be initialized when it is created as follows:

  Person me = {"Stephen", "Davis", 456789012};

Assignment is the only operation defined for user-defined classes by default. Its use is shown here:

  Person copyOfMe;
copyOfMe = me;   // copy each member of me to copyOfMe

The default assignment operator copies the members of the object on the right to the members on the left. The objects on the right and left of the assignment operator must be exactly the same type.

technicalstuff.eps You can define what the other operators might mean when applied to an object of a class that you define. That is considered advanced strokes, however, and is beyond the scope of this book.

Arrays of Objects

You can declare and initialize arrays of objects as follows:

  Person people[5] = {{   "Adam", "Laskowski", 123456789},
                    { "Kinsey",     "Davis", 234567890},
                    {  "Janet",    "Eddins", 345678901},
                    {"Stephen",     "Davis", 456789012},
                    {"Tiffany",    "Amrich", 567890123}};

The layout of people in memory is shown in Figure 19-2. Compare this with the parallel array equivalent in Figure 19-1.

9781118823873-fg1902.tif

Figure 19-2: The arrangement in memory of an array of five Person objects.

In this example, each one of the elements of the array people is an object. Thus, people[0] is the first object in the array. My information appears as people[3]. You can access the members of an individual member of an array of objects using the same “dot-member” syntax as that used for simple objects:

  // change my social security number
people[3].nSocialSecurityNumber = 456789012;

remember.eps The type of people is Person[], which is read “array of Person” (sometimes programmers use the plural of the class name as in “array of Persons”). The type of people[3] is Person.

Looking at an Example

I’ve gone far enough without an example program to demonstrate how class objects appear in a program. The following InputPerson program inputs the data for an array of people. It then sorts the array by Social Security number and outputs the sorted list.

warning.eps The sorting algorithm I used is known as a Bubble Sort. It isn’t particularly efficient, but it’s very simple to code. I explain how it works in a sidebar, but don’t get wrapped up in the details of the Bubble Sort. Focus instead on how the program inputs the critical elements of a Person into a single element of an array that it can then manipulate as a single entity.

  // InputPerson - create objects of class Person and
//               display their data
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;

// Person - stores the name and social security number
class Person
{
  public:
    char szFirstName[128];
    char szLastName[128];
    int  nSocialSecurityNumber;
};

// getPerson - read a Person object from the keyboard
//             and return a copy to the caller
Person getPerson()
{
    Person person;

    cout << " Enter another Person "
         << "First name: ";
    cin  >> person.szFirstName;

    cout << "Last name: ";
    cin  >> person.szLastName;

    cout << "Social Security number: ";
    cin  >> person.nSocialSecurityNumber;

    return person;
}

// getPeople - read an array of Person objects;
//             return the number read
int getPeople(Person people[], int nMaxSize)
{
    // keep going until operator says he's done or
    // until we're out of space
    int index;
    for(index = 0; index < nMaxSize; index++)
    {
        char cAnswer;
        cout << "Enter another name? (Y or N):";
        cin  >> cAnswer;

        if (cAnswer != 'Y' && cAnswer != 'y')
        {
            break;
        }

        people[index] = getPerson();
    }
    return index;
}

// displayPerson - display a person on the default display
void displayPerson(Person person)
{
    cout << "First name: " << person.szFirstName << endl;
    cout << "Last name : " << person.szLastName  << endl;
    cout << "Social Security number : "
         << person.nSocialSecurityNumber << endl;
}

// displayPeople - display an array of Person objects
void displayPeople(Person people[], int nCount)
{
    for(int index = 0; index < nCount; index++)
    {
        displayPerson(people[index]);
    }
}

// sortPeople - sort an array of nCount Person objects
//              by Social Security Number
//              (this uses a binary sort)
void sortPeople(Person people[], int nCount)
{
    // keep going until the list is in order
    int nSwaps = 1;
    while(nSwaps != 0)
    {
        // we can tell if the list is in order by
        // the number of records we have to swap
        nSwaps = 0;

        // iterate through the list...
        for(int n = 0; n < (nCount - 1); n++)
        {
            // ...if the current entry is greater than
            // the following entry...
            if (people[n].nSocialSecurityNumber >
                people[n+1].nSocialSecurityNumber)
            {
                // ...then swap them...
                Person temp  = people[n+1];
                people[n+1] = people[n];
                people[n]   = temp;

                // ...and count it.
                nSwaps++;
            }
        }
    }
}

int main(int nNumberofArgs, char* pszArgs[])
{
    // allocate room for some names
    Person people[128];

    // prompt the user for input
    cout << "Read name/social security information ";
    int nCount = getPeople(people, 128);

    // sort the list
    sortPeople(people, nCount);

    // now display the results
    cout << " Here is the list sorted by "
         << "social security number" << endl;
    displayPeople(people, nCount);

    // wait until user is ready before terminating program
    // to allow the user to see the program results
    cout << "Press Enter to continue..." << endl;
    cin.ignore(10, ' '),
    cin.get();
    return 0;
}

The program starts by declaring class Person with data members for first name, last name, and Social Security number. Contrary to good programming practice, this program uses fixed-length arrays for the name strings. (If I were writing this code for a commercial package, I would use variable-length arrays, or I would include a test to make sure that input from the keyboard did not overflow the buffer. See Chapter 17 if you don’t know what I’m talking about.)

The first function, getPerson(), prompts the user for the data necessary to describe a single Person object. It then returns a copy of that Person to the caller.

The second function, getPeople(), invokes the getPerson() function repeatedly to retrieve the data for a number of individuals. It stores the Person objects retrieved into the array people. This function accepts as an argument the maximum size of the people array and returns to the caller the actual number of elements stored there.

The displayPerson() and displayPeople() functions are the output analogs to the getPerson() and getPeople() functions. displayPerson() outputs the information for a single individual, whereas displayPeople() calls that function on each element defined in the people array.

The sortPeople() function sorts the elements of the people array in order of increasing Social Security number. This function is described in the “Bubble Sort” sidebar. Don’t worry too much about how this function works. You’re way ahead of the game if you can follow the rest of the program.

The output from a test run of this program appears as follows:

  Read name/social security information
Enter another name? (Y or N):y

Enter another Person
First name: Adam
Last name: Laskowski
Social Security number: 123456789
Enter another name? (Y or N):y

Enter another Person
First name: Stephen
Last name: Davis
Social Security number: 456789012
Enter another name? (Y or N):y

Enter another Person
First name: Janet
Last name: Eddins
Social Security number: 345678901
Enter another name? (Y or N):n

Here is the list sorted by social security number.
First name: Adam
Last name : Laskowski
Social Security number : 123456789
First name: Janet
Last name : Eddins
Social Security number : 345678901
First name: Stephen
Last name : Davis
Social Security number : 456789012
Press any key to continue …

You’ve seen most of the non-object-oriented features of C++. The next chapter introduces you to the Code::Blocks debugger, which wraps up the sections dedicated to what I call procedural programming. After that, I jump into object-oriented programming in Part V.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.9.147