Introduction
In Chapters 912, we discussed key object-oriented programming technologies including classes, objects, encapsulation, operator overloading and inheritance. We now continue our study of OOP by explaining and demonstrating polymorphism with inheritance hierarchies. Polymorphism enables us to "program in the general" rather than "program in the specific." In particular, polymorphism enables us to write programs that process objects of classes that are part of the same class hierarchy as if they are all objects of the hierarchy's base class. As we will soon see, polymorphism works off base-class pointer handles and base-class reference handles, but not off name handles.
Consider the following example of polymorphism. Suppose we create a program that simulates the movement of several types of animals for a biological study. Classes Fish, Frog and Bird represent the three types of animals under investigation. Imagine that each of these classes inherits from base class Animal, which contains a function move and maintains an animal's current location. Each derived class implements function move. Our program maintains a vector of pointers to objects of the various Animal derived classes. To simulate the animals' movements, the program sends each object the same message once per secondnamely, move. However, each specific type of Animal responds to a move message in its own unique waya Fish might swim two feet, a Frog might jump three feet and a Bird might fly ten feet. The program issues the same message (i.e., move) to each animal object generically, but each object knows how to modify its location appropriately for its specific type of movement. Relying on each object to know how to "do the right thing" (i.e., do what is appropriate for that type of object) in response to the same function call is the key concept of polymorphism. The same message (in this case, move) sent to a variety of objects has "many forms" of resultshence the term polymorphism.
With polymorphism, we can design and implement systems that are easily extensiblenew classes can be added with little or no modification to the general portions of the program, as long as the new classes are part of the inheritance hierarchy that the program processes generically. The only parts of a program that must be altered to accommodate new classes are those that require direct knowledge of the new classes that the programmer adds to the hierarchy. For example, if we create class Tortoise that inherits from class Animal (which might respond to a move message by crawling one inch), we need to write only the Tortoise class and the part of the simulation that instantiates a Tortoise object. The portions of the simulation that process each Animal generically can remain the same.
We begin with a sequence of small, focused examples that lead up to an understanding of virtual functions and dynamic bindingpolymorphism's two underlying technologies. We then present a case study that revisits Chapter 12's Employee hierarchy. In the case study, we define a common "interface" (i.e., set of functionality) for all the classes in the hierarchy. This common functionality among employees is defined in a so-called abstract base class, Employee, from which classes SalariedEmployee, HourlyEmployee and CommissionEmployee inherit directly and class BaseCommissionEmployee inherits indirectly. We will soon see what makes a class "abstract" or its opposite"concrete."
In this hierarchy, every employee has an earnings function to calculate the employee's weekly pay. These earnings functions vary by employee typefor instance, SalariedEmployees are paid a fixed weekly salary regardless of the number of hours worked, while HourlyEmployees are paid by the hour and receive overtime pay. We show how to process each employee "in the general"that is, using base-class pointers to call the earnings function of several derived-class objects. This way, the programmer needs to be concerned with only one type of function call, which can be used to execute several different functions based on the objects referred to by the base-class pointers.
A key feature of this chapter is its (optional) detailed discussion of polymorphism, virtual functions and dynamic binding "under the hood," which uses a detailed diagram to explain how polymorphism can be implemented in C++.
Occasionally, when performing polymorphic processing, we need to program "in the specific," meaning that operations need to be performed on a specific type of object in a hierarchythe operation cannot be generally applied to several types of objects. We reuse our Employee hierarchy to demonstrate the powerful capabilities of run-time type information (RTTI) and dynamic casting, which enable a program to determine the type of an object at execution time and act on that object accordingly. We use these capabilities to determine whether a particular employee object is a BasePlusCommissionEmployee, then give that employee a 10 percent bonus on his or her base salary.