This chapter continues our discussion of object-oriented programming (OOP) by introducing another of its key featuresinheritance. Inheritance is a form of software reuse in which the programmer creates a class that absorbs an existing class's data and behaviors and enhances them with new capabilities. Software reusability saves time during program development. It also encourages the reuse of proven, debugged, high-quality software, which increases the likelihood that a system will be implemented effectively.
When creating a class, instead of writing completely new data members and member functions, the programmer can designate that the new class should inherit the members of an existing class. This existing class is called the base class, and the new class is referred to as the derived class. (Other programming languages, such as Java, refer to the base class as the superclass and the derived class as the subclass.) A derived class represents a more specialized group of objects. Typically, a derived class contains behaviors inherited from its base class plus additional behaviors. As we will see, a derived class can also customize behaviors inherited from the base class. A direct base class is the base class from which a derived class explicitly inherits. An indirect base class is inherited from two or more levels up in the class hierarchy. In the case of single inheritance, a class is derived from one base class. C++ also supports multiple inheritance, in which a derived class inherits from multiple (possibly unrelated) base classes. Single inheritance is straightforwardwe show several examples that should enable the reader to become proficient quickly. Multiple inheritance can be complex and error prone. We cover multiple inheritance in Chapter 24, Other Topics.
C++ offers three kinds of inheritancepublic, protected and private. In this chapter, we concentrate on public inheritance and briefly explain the other two. In Chapter 21, Data Structures, we show how private inheritance can be used as an alternative to composition. The third form, protected inheritance, is rarely used. With public inheritance, every object of a derived class is also an object of that derived class's base class. However, base-class objects are not objects of their derived classes. For example, if we have vehicle as a base class and car as a derived class, then all cars are vehicles, but not all vehicles are cars. As we continue our study of object-oriented programming in Chapter 12 and Chapter 13, we take advantage of this relationship to perform some interesting manipulations.
Experience in building software systems indicates that significant amounts of code deal with closely related special cases. When programmers are preoccupied with special cases, the details can obscure the big picture. With object-oriented programming, programmers focus on the commonalities among objects in the system rather than on the special cases.
We distinguish between the is-a relationship and the has-a relationship. The is-a relationship represents inheritance. In an is-a relationship, an object of a derived class also can be treated as an object of its base classfor example, a car is a vehicle, so any properties and behaviors of a vehicle are also properties of a car. By contrast, the has-a relationship represents composition. (Composition was discussed in Chapter 10.) In a has-a relationship, an object contains one or more objects of other classes as members. For example, a car includes many componentsit has a steering wheel, has a brake pedal, has a transmission and has many other components.
Derived-class member functions might require access to base-class data members and member functions. A derived class can access the non-private members of its base class. Base-class members that should not be accessible to the member functions of derived classes should be declared private in the base class. A derived class can effect state changes in private base-class members, but only through non-private member functions provided in the base class and inherited into the derived class.
Software Engineering Observation 12.1
Software Engineering Observation 12.2
One problem with inheritance is that a derived class can inherit data members and member functions it does not need or should not have. It is the class designer's responsibility to ensure that the capabilities provided by a class are appropriate for future derived classes. Even when a base-class member function is appropriate for a derived class, the derived class often requires that member function to behave in a manner specific to the derived class. In such cases, the base-class member function can be redefined in the derived class with an appropriate implementation.