Polymorphism and virtual functions

(Carol Zander, CSS 343)

It is good to design so that systems are extensible. This means that general data and methods, common to all child classes are put in the parent class. Specific data and operations go into the child class. Sometimes though while a parent, say a Shape class, can specify the kind of task, e.g., draw, it cannot specify the implementation as it varies from object to object. E.g., drawing a circle is different from drawing a rectangle even though "draw" as a task is clear.

                  +-------------+ 
                  |    Shape    | 
                  | void draw() | 
                  +-------------+
                   /\        /\
                  /__\      /__\
                   |          |
                   |          |
                   |          |
            +---------+    +---------+       
            |  Oval   |    | Polygon |       
            +---------+    +---------+       
                 /\            /\
                /__\          /__\
                 |              |
                 |              |
                 |              |
            +--------+    +-----------+       
            | Circle |    | Rectangle |       
            +--------+    +-----------+       

Polymorphism -- the ability for objects of different classes related by inheritance to respond differently to the same member function call (similar to overloading of functions, but the signatures are the same and inheritance is implied). It is called overriding. A call to this kind of function is known as a polymorphic call.

Overloading -- two methods have different signatures.
Overriding -- two methods have the exact same signature.

Polymorphism is implemented using virtual functions.

Virtual functions

A function can be defined as virtual. A virtual function is how polymorphism is implemented. In general, being virtual means to use the child class method whenever possible. This only applies when the object is being viewed as being of the type of its parent. A virtual function is used by a child class when no function is defined. E.g., consider the list of Fruit example:
      Fruit* ptr;
      ptr = new Apple("carter");

The pointer to the Apple object is implicitly cast to be a Fruit pointer. Unless a virtual function is used with ptr, it is treated as a Fruit. For example, if the following code is used
      ptr->print();
if the print routine is virtual, then the Apple's print is used. If the print is not virtual, the Fruit's print is used.

Abstract/Concrete classes

When we define a class, we often want objects of that class, e.g., Rational. This is a concrete class.

Sometimes we don't want to instantiate objects of vague types. We want organization of our class hierarchy, but no objects. For example, in the shape hierarchy example, a shape is too vague to instantiate a shape object. If "draw" were a function, how would we draw it?

Pure Virtual functions

This is when an abstract class is appropriate. Objects cannot be instantiated of an abstract class. A class is abstract if it has at least one pure virtual function. Pure virtual functions have "= 0" and no body. E.g., Shape has pure virtual draw:       virtual void draw() const = 0;

If you inherit a pure virtual function, you MUST implement it. Any class that inherits a pure virtual function and doesn't provide an implementation is also abstract, i.e., the class inherits the function as pure virtual and so on down the hierarchy until it gets implemented.