Chapter 7 INHERITANCE One reason to use inheritance is that it allows 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. 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 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 _________________________________________________________________ Examine the file named VEHICLE.HPP for a simple =============== class which we will use to begin our study of VEHICLE.HPP inheritance in this chapter. 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 superclass 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. Ignore lines 4, 5, and 17 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 _________________________________________________________________ Examine the file named VEHICLE.CPP and you will find that it is the implementation of the vehicle class. The initialize() method Page 7-1 Chapter 7 - Inheritance assigns the values input as parameters to the =============== wheels and weight variables. We have methods to VEHICLE.CPP 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 superclass. 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 _________________________________________________________________ The file named TRANSPRT.CPP uses the vehicle ================ class in exactly the same manner as we TRANSPRT.CPP illustrated in the last chapter. This should be ================ an indication to you that this 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 superclass 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 points 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 superclass or subclass 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 SUBCLASS _________________________________________________________________ Examine the file named CAR.HPP for our first =============== example of the use of a subclass. The vehicle CAR.HPP class is inherited due to the ": public vehicle" =============== added to line 4. This class named car is composed of all of the information included in Page 7-2 Chapter 7 - Inheritance the superclass vehicle, and all of its own additional information. Even though we did nothing to the class named vehicle, we made it into a superclass because of the way we are using it here. To go a step further, even though it will be used as a superclass 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 single class and a superclass in the same program. The question of whether it is a simple class or a super 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 called a subclass, but the proper term as defined for C++ is a derived class. Since both terms are very descriptive, and most writers tend to use the terms interchangeably, we will also use both terms in this tutorial. A superclass is a rather general class which can cover a wide range of objects, whereas a subclass is somewhat more restricted but at the same time more useful. For example if we had a superclass named programming language and a subclass named C++, then we could use the superclass 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 subclass 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 superclass tends to be more general, and a subclass is more specific. In this case, the vehicle superclass 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 subclass of car and 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 subclass and a superclass at the same time, so it should be clear that these names refer to how a class is used. HOW DO WE DECLARE A SUBCLASS? _________________________________________________________________ Enough generalities about classes, let's get down to the specifics. A subclass is defined by including the header file for the superclass as is done in line 2, then the name of the superclass is given following the name of the subclass separated by a colon Page 7-3 Chapter 7 - Inheritance as is illustrated in line 4. Ignore the keyword public immediately following the colon in this line. It is optional 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. Note once again that the implementation for the superclass 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 superclass must be available as a text file since the class definitions are required in order to use the class. THE CAR CLASS IMPLEMENTATION _________________________________________________________________ Examine the file named CAR.CPP which is the =============== implementation file for the car class. The CAR.CPP first thing you should notice is that this file =============== has no indication of the fact that it is a subclass 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 subclass or not, it is written in exactly the same way as any other class implementation file. Line 8 contains a new construct. In order to initialize the variables which are a part of the superclass, we must send a message to the superclass. This is because the variables are private and directly available only within the class itself. We will see another way to do this in the next chapter of this tutorial. If you think you understand this file, you should compile it for later use. Keep in mind that you must have already compiled the vehicle class prior to this time in order to get a good compilation of this subclass. Page 7-4 Chapter 7 - Inheritance ANOTHER SUBCLASS _________________________________________________________________ Examine the file named TRUCK.HPP for an example =============== of another class that uses the vehicle class and TRUCK.HPP 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 methods. Once again, ignore the keyword public following the colon in line 4 for a few minutes and we will cover it in detail in the next chapter of this tutorial. 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 subclasses of the same superclass 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 superclass, 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 subclasses. THE TRUCK IMPLEMENTATION _________________________________________________________________ Examine the file named TRUCK.CPP for the =============== implementation of the truck class. It also has TRUCK.CPP a few unusual things included in it. In line 13 =============== of the second method, it uses a call to its superclass to get the weight of the truck. This is because the weight is private and therefore not available to the subclass but must be accessed via one of the superclass methods. There is a way to make it available here, but we will save that definition until the next chapter of this tutorial. You should have no problem understanding the remainder of this program. 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 _________________________________________________________________ Examine the example program named ALLVEHIC.CPP ================ for an example that uses all three of the ALLVEHIC.CPP classes we have been discussing in this chapter. ================ It uses the superclass vehicle to declare objects and also uses the two subclasses to Page 7-5 Chapter 7 - Inheritance 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 since 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 prior to any attempt to execute the final 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. WHY THE #ifndef VEHICLEHPP ? _________________________________________________________________ We promised to return to the strange looking preprocessor directive in lines 4, 5 and 17 in the VEHICLE.HPP file, and this is the time for it. When we define the subclass car, we are required to supply it with the full definition of the interface to the vehicle class since car is a subclass 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 main 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 redefine the class vehicle. Of course it is the same definition, Page 7-6 Chapter 7 - Inheritance but the system doesn't care, it simply doesn't allow redefinition 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 VEHICLEHPP. If the word is already defined, the definition is skipped, but if the word is not defined, the definition is included and the word 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 VEHICLEHPP was chosen as the word because it is the name of the file, with the period omitted. 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. It would be good for you to get into the practice of building the optional skip around all of your classes. MULTIPLE INHERITANCE _________________________________________________________________ Early implementations of C++ do not allow multiple inheritance, inheriting data and methods from more than one parent class. The newest versions of C++ permit multiple inheritance since the latest definition of the language (AT&T version 2.0 of C++), includes it as a part of its syntax. One of the biggest problems with multiple inheritance is the question of what should be done when both parent classes have methods of the same name. Some means must be available to decide which of the methods will actually be inherited. Chapter 9 of this tutorial will discuss multiple inheritance. Page 7-7 Chapter 7 - Inheritance PROGRAMMING EXERCISES _________________________________________________________________ 1. 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. 2. Add the optional skip around the header files of the classes named car and truck. Then recompile all four files and relink them to get an executable file. 3. 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.HPP, 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.HPP (TRUCK.HPP), CH07_3B.CPP (TRUCK.CPP) and the changed main program is found in CH07_3C.CPP in the answer directory on the distribution disk for this tutorial. Page 7-8