Skip to content

1.5. Introducing Classes

The only remaining feature we need to understand before solving our bookstore problem is how to define a data structure to represent our transaction data. In C++ we define our own data structures by defining a class. A class defines a type along with a collection of operations that are related to that type. The class mechanism is one of the most important features in C++. In fact, a primary focus of the design of C++ is to make it possible to define class types that behave as naturally as the built-in types.

In this section, we’ll describe a simple class that we can use in writing our bookstore program. We’ll implement this class in later chapters as we learn more about types, expressions, statements, and functions.

To use a class we need to know three things:

  • What is its name?
  • Where is it defined?
  • What operations does it support?

For our bookstore problem, we’ll assume that the class is named Sales_item and that it is already defined in a header named Sales_item.h.

As we’ve seen, to use a library facility, we must include the associated header. Similarly, we use headers to access classes defined for our own applications. Conventionally, header file names are derived from the name of a class defined in that header. Header files that we write usually have a suffix of .h, but some programmers use .H, .hpp, or .hxx. The standard library headers typically have no suffix at all. Compilers usually don’t care about the form of header file names, but IDEs sometimes do.

1.5.1. The Sales_item Class

The purpose of the Sales_item class is to represent the total revenue, number of copies sold, and average sales price for a book. How these data are stored or computed is not our concern. To use a class, we need not care about how it is implemented. Instead, what we need to know is what operations objects of that type can perform.

Every class defines a type. The type name is the same as the name of the class. Hence, our Sales_item class defines a type named Sales_item. As with the built-in types, we can define a variable of a class type. When we write

c++
Sales_item item;

we are saying that item is an object of type Sales_item. We often contract the phrase “an object of type Sales_item” to “a Sales_item object” or even more simply to “a Sales_item.”

In addition to being able to define variables of type Sales_item, we can:

  • Call a function named isbn to fetch the ISBN from a Sales_item object.
  • Use the input (>>) and output (<<) operators to read and write objects of type Sales_item.
  • Use the assignment operator (=) to assign one Sales_item object to another.
  • Use the addition operator (+) to add two Sales_item objects. The two objects must refer to the same ISBN. The result is a new Sales_item object whose ISBN is that of its operands and whose number sold and revenue are the sum of the corresponding values in its operands.
  • Use the compound assignment operator (+=) to add one Sales_item object into another.

INFO

Key Concept: Classes Define Behavior

The important thing to keep in mind when you read these programs is that the author of the Sales_item class defines all the actions that can be performed by objects of this class. That is, the Sales_item class defines what happens when a Sales_item object is created and what happens when the assignment, addition, or the input and output operators are applied to Sales_items.

In general, the class author determines all the operations that can be used on objects of the class type. For now, the only operations we know we can perform on Sales_item objects are the ones listed in this section.

Reading and Writing Sales_items

Now that we know what operations we can use with Sales_item objects, we can write programs that use the class. For example, the following program reads data from the standard input into a Sales_item object and writes that Sales_item back onto the standard output:

c++
#include <iostream>
#include "Sales_item.h"
int main()
{
    Sales_item book;
    // read ISBN, number of copies sold, and sales price
    std::cin >> book;
    // write ISBN, number of copies sold, total revenue, and average price
    std::cout << book << std::endl;
    return 0;
}

If the input to this program is

0-201-70353-X 4 24.99

then the output will be

0-201-70353-X 4 99.96 24.99

Our input says that we sold four copies of the book at $24.99 each, and the output indicates that the total sold was four, the total revenue was $99.96, and the average price per book was $24.99.

This program starts with two #include directives, one of which uses a new form. Headers from the standard library are enclosed in angle brackets (< >). Those that are not part of the library are enclosed in double quotes (" ").

Inside main we define an object, named book, that we’ll use to hold the data that we read from the standard input. The next statement reads into that object, and the third statement prints it to the standard output followed by printing endl.

Adding Sales_items

A more interesting example adds two Sales_item objects:

c++
#include <iostream>
#include "Sales_item.h"
int main()
{
    Sales_item item1, item2;
    std::cin >> item1 >> item2;   // read a pair of transactions
    std::cout << item1 + item2 << std::endl; // print their sum
    return 0;
}

If we give this program the following input

0-201-78345-X 3 20.00
0-201-78345-X 2 25.00

our output is

0-201-78345-X 5 110 22

This program starts by including the Sales_item and iostream headers. Next we define two Sales_item objects to hold the transactions. We read data into these objects from the standard input. The output expression does the addition and prints the result.

It’s worth noting how similar this program looks to the one on page 6: We read two inputs and write their sum. What makes this similarity noteworthy is that instead of reading and printing the sum of two integers, we’re reading and printing the sum of two Sales_item objects. Moreover, the whole idea of “sum” is different. In the case of ints we are generating a conventional sum—the result of adding two numeric values. In the case of Sales_item objects we use a conceptually new meaning for sum—the result of adding the components of two Sales_item objects.

INFO

Using File Redirection

It can be tedious to repeatedly type these transactions as input to the programs you are testing. Most operating systems support file redirection, which lets us associate a named file with the standard input and the standard output:

shellscript
$ addItems <infile >outfile

Assuming $ is the system prompt and our addition program has been compiled into an executable file named addItems.exe (or addItems on UNIX systems), this command will read transactions from a file named infile and write its output to a file named outfile in the current directory.

INFO

Exercises Section 1.5.1

Exercise 1.20:http://www.informit.com/title/032174113 contains a copy of Sales_item.h in the Chapter 1 code directory. Copy that file to your working directory. Use it to write a program that reads a set of book sales transactions, writing each transaction to the standard output.

Exercise 1.21: Write a program that reads two Sales_item objects that have the same ISBN and produces their sum.

Exercise 1.22: Write a program that reads several transactions for the same ISBN. Write the sum of all the transactions that were read.

1.5.2. A First Look at Member Functions

Our program that adds two Sales_items should check whether the objects have the same ISBN. We’ll do so as follows:

c++
#include <iostream>
#include "Sales_item.h"
int main()
{
    Sales_item item1, item2;
    std::cin >> item1 >> item2;
    // first check that item1 and item2 represent the same book
    if (item1.isbn() == item2.isbn()) {
        std::cout << item1 + item2 << std::endl;
        return 0;   // indicate success
    } else {
        std::cerr << "Data must refer to same ISBN"
                  << std::endl;
        return -1;  // indicate failure
    }
}

The difference between this program and the previous version is the if and its associated else branch. Even without understanding the if condition, we know what this program does. If the condition succeeds, then we write the same output as before and return 0, indicating success. If the condition fails, we execute the block following the else, which prints a message and returns an error indicator.

What Is a Member Function?

The if condition

c++
item1.isbn() == item2.isbn()

calls a member function named isbn. A member function is a function that is defined as part of a class. Member functions are sometimes referred to as methods.

Ordinarily, we call a member function on behalf of an object. For example, the first part of the left-hand operand of the equality expression

c++
item1.isbn

uses the dot operator (the .” operator) to say that we want “the isbn member of the object named item1.” The dot operator applies only to objects of class type. The left-hand operand must be an object of class type, and the right-hand operand must name a member of that type. The result of the dot operator is the member named by the right-hand operand.

When we use the dot operator to access a member function, we usually do so to call that function. We call a function using the call operator (the ()operator). The call operator is a pair of parentheses that enclose a (possibly empty) list of arguments. The isbn member function does not take an argument. Thus,

c++
item1.isbn()

calls the isbn function that is a member of the object named item1. This function returns the ISBN stored in item1.

The right-hand operand of the equality operator executes in the same way—it returns the ISBN stored in item2. If the ISBNs are the same, the condition is true; otherwise it is false.

INFO

Exercises Section 1.5.2

Exercise 1.23: Write a program that reads several transactions and counts how many transactions occur for each ISBN.

Exercise 1.24: Test the previous program by giving multiple transactions representing multiple ISBNs. The records for each ISBN should be grouped together.