Chapter 3: Inheritance

Chapter 3: Inheritance


Classes are often related to other classes. The two popular methods of relating classes are containment, also known as composition, and inheritance. Containment is a "has a" relationship, where a class contains or embeds another class. For example, a timestamp contains time. Inheritance is based on the "is a" relationship, in which one class is a type of another class. For example, an hourly employee is a kind of employee.

Inheritance involves a base type and a derived type, where a derived type is a kind of base type. Derived types inherit the members of the base type. In essence, they are derived from the base type.

A base type represents a generalization, whereas a derived type represents a specialty. Specialties are derivatives of generalizations. A personnel program might contain different types of employees. Hourly, salaried, commissioned, temporary, and retired are possible types of employees. Each is a kind of employee and distinct from any other employee specialization. For example, an hourly employee is different from a salaried employee. Employee is a generalization of all employees and is therefore a base class. Conversely, HourlyEmployee, SalariedEmployee, CommissionedEmployee, TemporaryEmployee, and RetiredEmployee are specializations and are therefore derived classes.

Derived types refine base types. A base type holds the common members of the generalization. Derived classes inherit those members and add specialty members. These members refine the base class in the context of the derived class. The Employee class, which is a base class, defines the FullName and EmplID members. Every employee has a name and employee number. As such, those members belong in the base type. The SalariedEmployee class adds members for the salary and number of pay periods. This is unique to the salaried employee specialization. The HourlyEmployee class has additional fields for the hourly rate and the number of hours worked. Both SalariedEmployee and HourlyEmployee classes refine the Employee class with these extra members.

Inheritance provides hierarchical clarity. The employee and derived types form a hierarchy. Without this clarity, you face a greater challenge in programming an application. Classes are analogous to marbles in a bin. A large bin holds hundreds of marbles. The bin is an indiscriminate jumble of marbles. From this jumble, you might try to find the one marble that is a clearie and has gray and white stripes. You could be looking for awhile, as shown in Figure 3-1. The marbles could be organized into separate bins for regular, boulder, and steelie marblies. Regular marbles are further segmented into cat's eyes and clearies, which are placed in smaller subcontainers. With this additional organization, finding the clearie with gray and white stripes is easier. (See Figure 3-2.)

Image from book
Figure 3-1: A basket of marbles
Image from book
Figure 3-2: Organized baskets of marbles

As part of the design phase, scenarios are often employed. The nouns in the scenarios are candidates for classes. Figure 3-3 shows the nouns found in a scenario for a Personnel application. There is no order or hierarchy. You should look for relationships. The "is a" or "is a kind of" phrases are excellent for identifying inheritance and discerning the base to derived class relationships. When the classes are organized by relationships, clarity blooms, as shown in Figure 3-4.

Image from book
Figure 3-3: Nouns from the Personnel scenario
Image from book
Figure 3-4: Nouns grouped by relationships

Class hierarchy in moderation is helpful. However, excessive hierarchy is as cumbersome as no hierarchy at all. An overly vertical hierarchy is as incoherent as a flat hierarchy. There are also performance penalties for extended class hierarchies. The best practice in C++ was to limit class hierarchies to six levels or fewer. For example, the copious layers of classes in Microsoft Foundation Classes (MFC) contributed to the complexity of the product. Wading through the extensive class hierarchy of the MFC is sometimes a tedious task. In addition, understanding the members of a class is harder when dozens of other classes seed that class with methods, properties, fields, and so on. Hierarchical clarity is lost, which affects your productivity. The Active Template Library (ATL) is on the opposite end of the spectrum and has a flatter model. It is trivial to navigate the ATL hierarchy, which is appreciated.

Inheritance also promotes code reuse. Without inheritance, common members would be implemented repeatedly—once in each derived type. Modifications would require updating several classes. This is a recipe for problems and is neither efficient nor versionable. Inheritance has a cascade effect, which is better. A member is implemented once in a base class, and the implementation cascades to all derived classes. Changes to a base member ripple to all descendants. Insert base members at the highest relevant point in the hierarchy. This creates the widest cascade and efficient utilization of the member. Inserting a member too low in the hierarchy forces related types to separately implement that member.

Reference types can inherit classes and interfaces. Inheriting a class exemplifies code reuse. The derived class inherits the members—including the code—of the base class. Conversely, an interface has no code. It is a contract. Types that implement the interface contract to implement every member of the interface, whereas the interface contracts to be immutable. This is important because changes to the interface would break any type derived from that interface. Value types and primitives are not inheritable; they are sealed. For example, you cannot inherit an int.

Value types cannot inherit other value types or classes. The exception is the System.ValueType class. Value types implicitly inherit the System.ValueType class. A struct can inherit interfaces.

Terminology is important. Accurate terminology enhances a conversation, whereas incorrect or unclear terminology muddles the discussion. Object-oriented analysis and design introduced a plethora of new terms, some of which are identical or similar. Some terms are intended for design, whereas others are for the implementation phase. However, this distinction is often lost. Table 3-1 shows a list of terms similar to base and derived types. In this chapter, the base/derived and parent/child terms are used interchangeably.

Table 3-1: Inheritance Terminology

Inheritable Class

Inheriting Class









Inheritance is not a mechanism to simply drop members into a class. From a design perspective, those members should belong in that class. For example, a timestamp has the properties of time and a stamp. A timestamp is a kind of stamp and has a time piece. However, a timestamp is not a kind of time. A TimeStamp class should inherit from the Stamp class but not the Time class. The "has a" relationship between the timestamp and time infers containment. Embedding a Time class in the TimeStamp class is the preferable implementation.