Inheritance is a fundamental component of the object-oriented paradigm. Understandably, there are many different ways of defining and understanding it. The original UML authors, Booch, Rumbaugh, & Jacobson1, formally define inheritance as "The mechanism by which more-specific elements incorporate the structure and behavior of more-general elements" (p. 456). That is, the top class in an inheritance hierarchy represents a general "thing," and lower classes are more specific. Less formally, the relationship means that given two classes related by inheritance, one class defines some members (variables and functions), and the other class inherits and can use them. All the different ways of defining or looking at inheritance follow from this mechanism.
Inheritance is a complex and abstract concept describing how two classes relate. We can make the idea more concrete with a graphical representation or picture of the related classes. We can also make it easier to discuss inheritance if we distinguish and label the various roles played by each class.
Inheritance is an important and complex relationship, with many ways to define or understand it. The following figures explore some of the many aspects of this vital class relationship.
Generalization
What do Booch, Rumbaugh, and Jacobson mean when they speak of "more-specific elements" and "more-general elements?"
Inheritance as generalization. In the context of object orientation, generalization is a synonym for inheritance. We can illustrate this with a more concrete example based on a Car and a Sedan. Inheritance is often called an is-a or an is-a kind-of relationship (read from the subclass to the superclass). For example, "a Sedanis-aCar" or "a Sedanis-a kind-ofCar." In this example, generalization suggests that all Sedans are Cars, but not all Cars are Sedans - some are Convertibles. Finally, it doesn't sound right (at least in English) to say, "a Sedan has-a Car." Listening to how the description of a relationship sounds can help us choose the best relationship and build it in the correct direction.
Inheritance is alternately known as generalization because classes appearing at or near the top of an inheritance hierarchy represent general classes. At the same time, those at or near the bottom are more specialized. So, a Car is general - there are many different kinds of Cars. Alternatively, Sedans and Convertibles are more specialized kinds of Cars. There isn't a syntactic limit to the number of subclasses a superclass may have: an inheritance hierarchy can be arbitrarily wide and tall.
The two inheritance diagrams are equivalent: the version on the left combines the arrowheads, which is useful when there are many subclasses, while the one on the right uses a separate arrowhead for each inheritance connector.
Inheriting Features
What do Booch, Rumbaugh, and Jacobson mean when they suggest one class can "incorporate the structure and behavior" of another? Or, as I suggested, that a class can use the features defined in another class?
Inheriting functions and variables. A superclass's ability to share its features with its subclasses is one of the most important aspects of inheritance. If we were to write an object-oriented program to automate a bank or credit union, we might find it convenient to create a general Account class and several specialized kinds of accounts, such as Loan. An Account has a name, an account ID, and a balance. Through inheritance, a Loanis-a special kind of Account, and it inherits the name, account ID, and balance - it has and can use these members without redefining them.
The Loan payment function can call the setter and getter functions in the Account class, which in turn access the Account's private member variables. An instance of the Loan class (carLoan in this example) can call any public functions in the Account class (e.g., getBalance) in addition to any public functions defined in the Loan class (e.g., payment). In this sense, inheritance is a way to reuse code in a program. While we have used functions to reuse code in the past, inheritance gives us a way, at least to some extent, to also reuse variables.
Similarities Versus Differences
Before joining the UML team, Rumbaugh2 and his group at General Electric created the Object Modeling Technique (OMT), one of the languages unified into the UML. They defined inheritance as a descriptive abstraction "for sharing the similarities among classes while preserving their differences" (p. 38).
Inheritance And Objects
The Venn diagram illustrating the similarities and differences between a super and subclass also suggests how the inheritance relationship is implemented, at least in part.
Substitutability
Fowler3 explains that "An important principle of using inheritance effectively is substitutability. I should be able to substitute a [subclass] within any code that requires a [superclass], and everything should work fine" (pp. 45-46). Si Alhir4 (1998) adds that while "a subclass instance may be substituted where a superclass instance is required... The reverse is not true, however: a superclass cannot be substituted for a subclass" (p. 61). Substitutability and its directional nature are a consequence of the similarities and differences between super- and subclasses: a subclass has everything that a superclass has but not vice versa. In a later chapter, we'll expand the concept of substitutability into the fundamental concept of polymorphism.
Substitutability. We begin with a general Shape class with three more specialized subclasses: Circle, Rectangle, and Triangle. First, it makes sense to say that "a Circleis-aShape," and similarly for Rectangle and Triangle. Now, suppose that some C++ code (the render function) requires a Shape object; substitutability implies that we may substitute a Circle, a Rectangle, or a Triangle in place of the Shape. (The illustrated syntax is an oversimplification we'll refine in a subsequent chapter.) Substitutability is the starting point for polymorphism, the final requirement for full object orientation, and the topic of a subsequent chapter.
Inheritance Summary: Filling In The Table
Inheritance has some property values in common with other class relationships, but it has one unique, distinguishing characteristic: It is the only relationship forming an "is-a" binding between classes. The following figure summarizes the property values presented above. Use the summary to check and complete your entries in one of the blank Class Relationship Tables located at the end of the chapter.
Class Roles. The relationship forms a class hierarchy. The first class plays the role of the Parent or Superclass; the second class is the Child or Subclass.
Semantics. Inheritance is the only is-a relationship, so its semantics or meaning is the fundamental difference between inheritance and the other relationships. In terms of the inheritance hierarchy illustrated in Figure 6 above:
a Circle is-a Shape
a Rectangle is-a Shape
a Triangle is-a Shape
Directionality. Inheritance is a unidirectional or a one-way relationship. Unidirectionality means that
(a)
(b)
(c)
(d)
The operations may only take place in one direction: from the child to the parent
The subclass or child object can send a message to the superclass or parent object, which can respond to a child's messages but cannot initiate message sending
The child "knows" about the parent, but the parent doesn't "know" about the child
It is possible to navigate from the child to the parent object but not from the parent to the child
Binding Strength. The binding between the two objects is very strong or tight because the superclass or parent object is embedded inside the subclass or child object (Figure 5). The strength of the bond implies the final two characteristics:
Lifetime. The two objects have a coincident lifetime, which means that the two objects are created and destroyed at the same time. It also means that the relationship between the two objects is permanent - it cannot be altered or broken.
Sharing. The binding between the two objects is so tight or strong that it forms an exclusive relationship - the subclass or child object does not share its superclass or parent object with any other object in the program.
C++ implementation.
class Circle : public Shape
{
. . .
};
Inheritance property values. Inheritance is the only class relationship with a dedicated implementation syntax; C++ implements the other relationships with member variables. Inheritance is necessary for upcasting, function overriding, and polymorphism - all covered in the polymorphism chapter.
1 Booch, G., Rumbaugh, J., & Jacobson, I. (2005). The unified modeling language user guide (2nd ed.). Upper Saddle River, NJ: Addison-Wesley.
2 Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F., & Lorensen, W. (1991). Object-Oriented Modeling and Design. Englewood Cliffs, NJ: Prentice Hall.
3 Fowler, M. (2004). UML distilled: A brief guide to the standard object modeling language. Boston: Addison-Wesley.
4 Si Alhir, S. (1998). UML In A Nutshell: A Desktop Quick Reference. Cambridge, MA: O'Reilly & Associates.