Polymorphism

Polymorphism is the ability for objects of different classes related by inheritance to respond differently to the same member function call.

display() for an Employee object:
  ID: 123
  NAME: Joe Smith
  DEPT: 34

display() for an HourlyEmployee:
  ID: 456
  WAGE: $5.50
  HOURS WORKED: 20

display() for a SalariedEmployee:
  ID: 789
  NAME: Jane Doe
  DEPT: 90
  SALARY: $65000.00

This can cause problems though because of "compile-time" or "static" binding.

Employee emp1(123, "Joe", "Smith", 34);
HourlyEmployee emp2(456, "Mike", "Jones", 67, 5.50, 20);
SalariedEmployee emp3(789, "Jane", "Doe", 90, 65000.00);

cout << emp1 << '\n'
     << emp2 << '\n'
     << emp3;

will produce:

ID: 123
NAME: Joe Smith
DEPT: 34

ID: 456
NAME: Mike Jones
DEPT: 67

ID: 789
NAME: Jane Doe
DEPT: 90

What we need to happen is for the binding to be delayed until run time so that the correct type of object can be determined.

In order to accomplish "run-time", "late", or "dynamic" binding we must use virtual functions.

Virtual Functions

A virtual function allows a programmer to call a function and let the program determine dynamically which version of the function to use.

To enable this type of behavior, the function will be declared in the base class as a virtual function and then be redefined in each of the derived classes.

To declare a virtual function, precede the function’s prototype with the keyword virtual in the base class.

in the Employee class definition:

   virtual void display(ostream &);


Employee emp1(123, "Joe", "Smith", 34);
HourlyEmployee emp2(456, "Mike", "Jones", 67, 5.50, 20);
SalariedEmployee emp3(789, "Jane", "Doe", 90, 65000.00);

cout << emp1 << '\n'
     << emp2 << '\n'
     << emp3;

will produce:

ID: 123
NAME: Joe Smith
DEPT: 34

ID: 456
WAGE: $5.50
HOURS WORKED: 20

ID: 789
NAME: Jane Doe
DEPT: 90
SALARY: $65000.00

Once a function is declared as virtual in a class, it remains virtual in all of the classes derived from the class.

Abstract Classes

When we think of a class as a type, we assume that objects of that type will be created. However, there are situations in which it is useful to define classes that will never have objects created from them. These type of classes are known as abstract classes or abstract base classes.

Once a class is made abstract, no objects can be created from it.

The sole purpose of an abstract class is to provide an appropriate base class from which classes may inherit interface and/or implementation. Classes that are derived from abstract classes are known as concrete classes.

For example, we could have an abstract class Shape and derive concrete classes such as Square, Circle, or Triangle. Or maybe, Form and derive License, Certificate or Report.

The abstract classes are too generic to define real objects. We need to be more specific before an object can be created. That is the purpose of concrete classes. They provide the specifics that make it reasonable to create objects.

To create an abstract class, one or more of the virtual functions must be made a pure virtual function.

A pure virtual function is a virtual function that has an initializer of = 0 in its declaration and is never implemented in the class in which it is declared.

For example: virtual float earnings() = 0; is the definition for a pure virtual function

The function will be defined in the classes that are derived from the abstract class.

If a class is derived from an abstract class and no definition is supplied for the pure virtual function in the derived class, the function will remain a pure virtual function in the derived class. Therefore the derived class is also an abstract class.

Suppose that we have the abstract class Form:

class Form
  {
  public:
    virtual void display(ostream &out) = 0;
    virtual void read(istream &in) = 0;
  ...
  };

We could then derive from it:

class License : public Form
  {
  public:
    virtual void display(ostream &);
    virtual void read(istream &);
    ...
    
  protected:
    int idNumber;
    string firstName, lastName;
    int age;
    ...
  };
  
void License::display(ostream &out)
  {
  out << idNumber << ' '
      << firstName << ' ' << lastName '\n'
      << "Age: " << age;
  }

***********************************************************************

class PetLicense : public License
  {
  public:
    void display(ostream &);
    ...
    
  protected:
    string petType;
    ...
  };
  
void PetLicense::display(ostream &out)
  {
  License::display(out);
  
  out << "Pet type: " << petType;
  }