In Object Oriented Programming Inheritance is the process by which objects of one class acquire the properties and functionality of objects of another class. It supports the concept of hierarchical classification. For example, the bird robin is a part of the class flying bird which is again a part of the class bird.

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. Moreover, it is easy to make an error if we try to modify the original class, but we are less likely to make an error if we 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 the last tutorial we developed a model using modes of transportation to illustrate the concept of inheritance. In this chapter we will use that model to illustrate some of the finer points of inheritance and what it can be used for.

REORGANIZED FILE STRUCTURE

A close examination of the file named INHERIT1.CPP will reveal that it is identical to the program developed in chapter 7 named ALLVEHIC.CPP except that the program text is rearranged.

//inherit1.cpp
#include <iostream.h>

class vehicle {
protected:
int wheels;
float weight;
public:
void initialize(int in_wheels, float in_weight);
int get_wheels(void) {return wheels;}
float get_weight(void) {return weight;}
float wheel_loading(void) {return weight/wheels;}
};

class car : public vehicle {
int passenger_load;
public:
void initialize(int in_wheels, float in_weight, int people = 4);
int passengers(void) {return passenger_load;}
};

class truck : public vehicle {
int passenger_load;
float payload;
public:
void init_truck(int how_many = 2, float max_load = 24000.0);
float efficiency(void);
int passengers(void) {return passenger_load;}
};

main()
{
vehicle unicycle;

unicycle.initialize(1, 12.5);
cout << "The unicycle has " <<
unicycle.get_wheels() << " wheel.n";
cout << "The unicycle's wheel loading is " <<
unicycle.wheel_loading() << " pounds on the single tire.n";
cout << "The unicycle weighs " <<
unicycle.get_weight() << " pounds.nn";

car sedan;

sedan.initialize(4, 3500.0, 5);
cout << "The sedan carries " << sedan.passengers() <<
" passengers.n";
cout << "The sedan weighs " << sedan.get_weight() << " pounds.n";
cout << "The sedan's wheel loading is " <<
sedan.wheel_loading() << " pounds per tire.nn";

truck semi;

semi.initialize(18, 12500.0);
semi.init_truck(1, 33675.0);
cout << "The semi weighs " << semi.get_weight() << " pounds.n";
cout << "The semi's efficiency is " <<
100.0 * semi.efficiency() << " percent.n";
}

// initialize to any data desired
void
vehicle::initialize(int in_wheels, float in_weight)
{
wheels = in_wheels;
weight = in_weight;
}

void
car::initialize(int in_wheels, float in_weight, int people)
{
passenger_load = people;
wheels = in_wheels;
weight = in_weight;
}

void
truck::init_truck(int how_many, float max_load)
{
passenger_load = how_many;
payload = max_load;
}

float
truck::efficiency(void)
{
return payload / (payload + weight);
}
// Result of execution
//
// The unicycle has 1 wheel.
// The unicycle's wheel loading is 12.5 pounds on the single tire.
// The unicycle weighs 12.5 pounds.
//
// The sedan carries 5 passengers.
// The sedan weighs 3500 pounds.
// The sedan's wheel loading is 875 pounds per tire.
//
// The semi weighs 12500 pounds.
// The semi's efficiency is 72.929072 percent.

The biggest difference is that some of the simpler methods in the classes have been changed to inline code to shorten the file considerably. In a practical programming situation, methods that are this short should be programmed inline since the actual code to return a simple value is shorter than the code required to send a message to a non-inline method.

The only other change is the reordering of the classes and associated methods with the classes all defined first, followed by the main program. This puts all class interface definitions on a single page to make the code easier to study. The implementations for the methods are deferred until the end of the file where they are available for quick reference but are not cluttering up the class definitions which we wish to study carefully in this chapter. This should be an indication to you that there is considerable flexibility in the way the classes and methods can be arranged in C++. Of course you realize that this violates the spirit of C++ and its use of separate compilation, but is only done here for convenience. The best way to package all of the example programs in this chapter is like the packaging illustrated in chapter 7.

As mentioned before, the two derived classes, car and truck, each have a variable named passenger_load which is perfectly legal, and the car class has a method of the same name, initialize(), as one defined in the super-class named vehicle. The rearrangement of the files in no way voids this allowable repeating of names.

After you have convinced yourself that this program is truly identical to the program named ALLVEHIC.CPP from chapter 7, compile and execute it with your compiler to assure yourself that this

arrangement is legal. Due to this means of code packaging, you will not need a “make” file or a “project” capability to compile and execute this code. This is to make it easy to compile and execute the example programs in this chapter.

THE SCOPE OPERATOR

Because the method initialize() is defined in the derived car class, it hides the method of the same name which is part of the base class, and there may be times you wish to send a message to the method in the base class for use in the derived class object. This can be done by using the scope operator in the following manner in the main program;

sedan.vehicle::initialize(4, 3500.0);

As you might guess, the number and types of parameters must agree with those of the method in the base class because it will respond to the message.