|
 |
[Introduction] [Chapter 1] [Chapter
2] [Chapter 3] [Chapter
4] [Chapter 5] [Chapter
6] [ Chapter 7 ] [Chapter
8] [Chapter 9] [Chapter
10] [Chapter 11] [Chapter
12]
Chapter 7: Inheritance
One reason to use inheritance is that it permits you to reuse code from
a previous project, but gives you the flexibility to slightly modify
it if the old code doesn't do exactly what you need for the new project.
It doesn't make sense to start every new project from scratch since
some code will certainly be repeated in several programs and you should
strive to build on what you did previously. However, it is easy to make
an error if you try to modify the original class. You are less likely
to make an error if you leave the original alone and only add to it.
Another reason for using inheritance is if the project requires the
use of several classes which are very similar but slightly different.
In this chapter we will concentrate on the mechanism of inheritance
and how to build it into a program. A better illustration of why you
would use inheritance will be given in later chapters where we will
discuss some practical applications of object oriented programming.
The principle of inheritance is available with several modern programming
languages and is handled slightly differently with each. C++ allows
you to inherit all or part of the members and methods of a class, modify
some, and add new ones not available in the parent class. You have complete
flexibility, and as usual, the method used with C++ has been selected
to result in the most efficient code execution.
A SIMPLE CLASS TO START WITH
Example program > VEHICLE.H

Examine the file named VEHICLE.H for a simple class which we will use
to begin our study of inheritance. There is nothing unusual about this
class header, it has been kept very simple. It consists of four simple
methods which can be used to manipulate data pertaining to our vehicle.
What each method does is not especially important at this time. We will
eventually refer to this as a base class or parent class, but for the
time being, we will simply use it like any other class to show that
it is indeed identical to the classes already studied. Note that we
will explain the added keyword protected
shortly. Figure 7-1 is a graphical representation of the vehicle
class. Ignore lines 4, 5, and 19 until the end of this
chapter where they will be explained in detail. This file cannot be
compiled or executed because it is only a header file.
THE IMPLEMENTATION FOR VEHICLE
Example program > VEHICLE.CPP
Examine the file named VEHICLE.CPP and you will find that it is the
implementation of the vehicle class.
The initialize() method assigns
the values input as parameters to the wheels
and weight variables. We
have methods to return the number of wheels
and the weight, and finally,
we have one that does a trivial calculation to return the loading on
each wheel. We will have a few examples of methods that do some significant
processing later, but at this point, we are more interested in learning
how to set up the interface to the classes, so the implementations will
be kept trivial.
As stated above, this is a very simple class which will be used in the
next program. Later in this tutorial we will use it as a base class.
You should compile this class at this time in preparation for the next
example program, but you cannot execute it because there is no entry
point.
USING THE VEHICLE CLASS
Example program > TRANSPRT.CPP
The file named TRANSPRT.CPP uses the vehicle
class in exactly the same manner as we illustrated in the last
chapter. This should be an indication to you that the vehicle
class is truly nothing more than a normal class as defined in
C++. We will make it a little special, however, by using it unmodified
as a base class in the next few example files to illustrate inheritance.
Inheritance uses an existing class and adds functionality to it to accomplish
another, possibly more complex job.
You should have no problem understanding the operation of this program.
It declares four objects of the vehicle
class, initializes them, and prints out a few of the data values
to illustrate that the vehicle class
can be used as a simple class because it is a simple class. We are referring
to it as a simple class as opposed to calling it a base class or derived
class as we will do shortly.
If you thoroughly understand this program, you should compile and execute
it, remembering to link the vehicle object
file with this object file.
OUR FIRST DERIVED CLASS
Example program > CAR.H
Examine the file named CAR.H for our first example of the use of a derived
class or child class. The vehicle class
is inherited due to the ": public vehicle"
added to line 7. This derived class named car
is composed of all of the information included in the base class
vehicle, and all of its own additional
information. Even though we did nothing to the class named vehicle,
we made it into a base class because of the way we are using it here.
To go a step further, even though it will be used as a base class in
an example program later in this chapter, there is no reason it cannot
continue to be used as a simple class in the previous example program.
In fact, it can be used as a simple class and a base class in the same
program. The question of whether it is a simple class or a base class
is answered by the way it is used. A discussion of terminology is needed
here. When discussing object oriented programming in general, a class
that inherits another is often called a derived class or a child class,
but the most proper term as defined for C++, is a derived class. Since
these terms are very descriptive, and most writers tend to use the terms
interchangeably, we will also use these terms in this tutorial. Likewise
the proper C++ terminology for the inherited class is to call it a base
class, but parent class and super class are sometimes used also.
A base class is a rather general class which can cover a wide range
of objects, whereas a derived class is somewhat more restricted but
at the same time more useful. For example if we had a base class named
programming language and a derived class named C++, then we could use
the base class to define Pascal, Ada, C++, or any other programming
language, but it would not tell us about the use of classes in C++ because
it can only give a general view of each language. On the other hand,
the derived class named C++ could define the use of classes, but it
could not be used to describe the other languages because it is too
narrow. A base class tends to be more general, and a derived class is
more specific.
In this case, the vehicle base
class can be used to declare objects that represent trucks, cars, bicycles,
or any number of other vehicles you can think up. The class named car
however can only be used to declare an object that is of type
car because we have limited the
kinds of data that can be intelligently used with it. The car
class is therefore more restrictive and specific than the vehicle
class. The vehicle class
is more general than the car class. If we wished to get even more
specific, we could define a derived class using car
as the base class, name it sports_car,
and include such information as red_line_limit
for the tachometer which would be silly for the family station wagon.
The car class would therefore
be used as a derived class and a base class at the same time, so it
should be clear that these names refer to how a class is used.
HOW DO WE DECLARE A DERIVED CLASS?
Enough generalities about classes, let's get down to the specifics.
A derived class is defined by including the header file for the base
class as is done in line 5, then the name of the base class is given
following the name of the derived class separated by a colon as is illustrated
in line 7. Ignore the keyword public
immediately following the colon in this line. This defines public
inheritance and we will study it in detail in the next chapter. All
objects declared as being of class car
therefore are composed of the two variables from the class vehicle
because they inherit those variables, and the single variable
declared in the class car named
passenger_load.

An object of this class will have three of the four methods of vehicle
and the two new ones declared here. The method named initialize()
which is part of the vehicle class
will not be available here because it is hidden by the local version
of initialize() which is a part
of the car class. The local method
will be used if the name is repeated allowing you to customize your
new class. Figure 7-2 is a graphical representation of an object of
this class.
Note once again that the implementation for the base class only needs
to be supplied in its compiled form. The source code for the implementation
can be hidden for economic reasons to aid software developers. Hiding
the source code also allows the practice of information hiding. The
header for the base class must be available as a text file since the
class definitions are required in order to use the class.
THE CAR CLASS IMPLEMENTATION
Example program > CAR.CPP
Examine the file named CAR.CPP which is the implementation file for
the car class. The first thing
you should notice is that this file has no indication of the fact that
it is a derived class of any other file, that can only be determined
by inspecting the header file for the class. Since we can't tell if
it is a derived class or not, it is written in exactly the same way
as any other class implementation file.
The implementations for the two new methods are written in exactly the
same way as methods are written for any other class. If you think you
understand this file, you should compile it for later use.
ANOTHER DERIVED CLASS
Example program > TRUCK.H
Examine the file named TRUCK.H for an example of another class that
uses the vehicle class and adds
to it. Of course, it adds different things to it, because it will specialize
in those things that pertain to trucks. In fact, it adds two more variables
and three more methods. Once again, ignore the keyword public
following the colon in line 7 for a few minutes and we will cover
it in detail in the next chapter of this tutorial. See figure 7-3 for
a graphical representation of the truck
class.

A very important point that must be made is that the car
class and the truck class
have absolutely nothing to do with each other, they only happen to be
derived classes of the same base class or parent class as it is sometimes
called.
Note that both the car and the
truck classes have methods named
passengers() but this causes no
problems and is perfectly acceptable. If classes are related in some
way, and they certainly are if they are both derived classes of a common
base class, you would expect them to be doing somewhat similar things.
In this situation there is a good possibility that a method name would
be repeated in both child classes.
THE TRUCK IMPLEMENTATION
Example program > TRUCK.CPP
Examine the file named TRUCK.CPP for the implementation of the truck
class. It has nothing unusual included in it.
You should have no problem understanding this implementation. Your assignment
at this point is to compile it in preparation for our example program
that uses all three of the classes defined in this chapter.
USING ALL THREE CLASSES
Example program > ALLVEHIC.CPP
Examine the program named ALLVEHIC.CPP for an example that uses all
three of the classes we have been discussing in this chapter. It uses
the parent class vehicle to declare
objects and also uses the two child classes to declare objects. This
was done to illustrate that all three classes can be used in a single
program.
All three of the header files for the classes are included in lines
3 through 5 so the program can use the components of the classes. Notice
that the implementations of the three classes are not in view here and
do not need to be in view. This allows the code to be used without access
to the source code for the actual implementation of the class. However,
it should be clear that the header file definition must be available.
In this example program, only one object of each class is declared and
used but as many as desired could be declared and used in order to accomplish
the programming task at hand. You will notice how clean and uncluttered
the source code is for this program. The classes were developed, debugged,
and stored away previously, and the interfaces were kept very simple.
There is nothing new here so you should have no trouble understanding
the operation of this program.
Compiling and executing this program will take a bit of effort but the
process is not complicated. The three classes and the main()
program can be compiled in any order desired. All four must be
compiled prior to linking the four resulting object (or binary) files
together. Finally, you can execute the complete program. Be sure you
do the required steps to compile and execute this program because the
effective use of C++ will require you to compile many separate files
and link them together. This is because of the nature of the C++ language,
but it should not be a burden if a good "make" capability exists with
your compiler. If you are using an implementation of C++ that has a
"project" capability, it will make this a snap.
WHY THE #ifndef VEHICLE_H ?
We promised to return to the strange looking preprocessor directive
in lines 4, 5 and 19 in the VEHICLE.H file, and this is the time for
it. When we define the derived class car,
we are required to supply it with the full definition of the interface
to the vehicle class since car
is a derived class of vehicle
and must know all about its parent. We do that by including the
vehicle class into the car
class, and the car class
can be compiled. The vehicle class
must also be included in the header file of the truck
class for the same reason.
When we get to the ALLVEHIC.CPP program, we must inform it of the details
of all three classes, so all three header files must be included as
is done in lines 3 through 5 of ALLVEHIC.CPP, but this leads to a problem.
When the preprocessor gets to the car
class, it includes the vehicle
class because it is listed in the car
class header file, but since the vehicle
class was already included in line 3 of ALLVEHIC.CPP, it is included
twice and we attempt to redeclare the class vehicle.
Of course it is the same declaration, but the system doesn't care, it
simply doesn't allow redeclaration of a class. We allow the double inclusion
of the file and at the same time prevent the double inclusion of the
class by building a bridge around it using the word VEHICLE_H. If the
word is already defined, the declaration is skipped, but if the word
is not defined, the declaration is included and VEHICLE.H is defined
at that time. The end result is the actual inclusion of the class only
once, even though the file is included more than once. You should have
no trouble understanding the logic of the includes if you spend a little
time studying this program sequence.
Even though ANSI-C allows multiple definitions of entities, provided
the definitions are identical, C++ does not permit this. The primary
reason is because the compiler would have great difficulty in knowing
if it has already made a constructor call for the redefined entity,
if there is one. A multiple constructor call for a single object could
cause great havoc, so C++ was defined to prevent any multiple constructor
calls by making it illegal to redefine any entity. This is not a problem
in any practical program.
The name VEHICLE_H was chosen as the word because it is the name of
the file, with the period replaced by the underline. If the name of
the file is used systematically in all of your class definitions, you
cannot have a name clash because the filename of every class must be
unique provided you keep all files in the same directory. It would be
good for you to get into the practice of building the optional skip
around all of your class headers. All class definition files in the
remainder of this tutorial will include this skip around to prevent
multiple inclusions and to be an example for you. You should get into
the practice of adding the skip around to all of your class headers
no matter how trivial they may seem to be.
OUR FIRST PRACTICAL INHERITANCE
Example program > NEWDATE.H
Continuing where we started in chapter 5, we will inherit the date
class into the file named NEWDATE.H and add a member variable
and a new method to the class. Actually, this is not a good way to add
the day_of_year to the date
class since it is available in the structure returned from the
system call in the date class.
However, we are more interested in illustrating inheritance in a practical
example than we are in developing a perfect class, so we will live with
this inefficiency. You will note that we add one variable and one method
to create our new class.
Example program > NEWDATE.CPP
The program named NEWDATE.CPP contains the implementation for the added
method and should be easy for the student to understand. This class
implementation uses the array days[]
from the date class implementation
since it was defined as a global variable there. The method named get_time_of_day()
involves very simple logic. It doesn't even adjust for leap years. Once
again, we are not really interested in writing a good date
class, but in learning the mechanics of inheritance.
Example program > TRYNDATE.CPP
Finally, the example program named TRYNDATE.CPP will use the new class
in a very simple way to illustrate that the derived class is as easy
to use as the base class and in fact the main program has no way of
knowing that it is using a derived class.
You should compile and link this program to gain the experience of doing
so. Remember that it will be necessary to link in the object code for
the original date class as well
as the object code from the newdate class
and the main() program.
PROGRAMMING EXERCISES
- Add another object of the vehicle class to ALLVEHIC.CPP named
bicycle, and do some of the same operations as were done to the
unicycle. You will only need to recompile the main() program and
link all four files together to get an executable file, the three
classes will not require recompilation.
- Add a new method to the truck class to return the total weight
of the truck plus its payload and add code to ALLVEHIC.CPP to
read the value out and display it on the monitor. This will require
an addition to TRUCK.H, another addition to TRUCK.CPP, and of
course the changes to the main program named ALLVEHIC.CPP. The
answer is given as three files named CH07_3A.H (TRUCK.H), CH07_3B.CPP
(TRUCK.CPP) and the changed main() program is found in CH07_3C.CPP
in the answers for this tutorial.
- Add a variable named sex of type char to the name class you developed
in chapter 5 as well as methods to set and retrieve the value
of this variable. The only legal inputs are 'M' or 'F'. These
additions should be done by inheriting the name class into the
new class.
<< back next >>
[Introduction] [Chapter 1] [Chapter
2] [Chapter 3] [Chapter
4] [Chapter 5] [Chapter
6] [ Chapter 7 ] [Chapter
8] [Chapter 9] [Chapter
10] [Chapter 11] [Chapter
12] |
|