Chapter 21 - Polymorphism


Chapter Goals



21.1 Class Inheritance Hierarchies


21.1 Class Inheritance Hierarchies (cont.)


21.1 Class Inheritance Hierarchies (cont.)


21.1 Class Inheritance Hierarchies (cont.)


21.2 Polymorphic Variables


21.2 Polymorphic Variables - example

class Employee
{
public:
   Employee(string n, double s);
   string get_name() const;
   double get_salary() const;
   void set_salary(double s);
   virtual double annual_income() const;
   void print(ostream& out) const;
private:
   string name;
   double salary;
};

21.2 Polymorphic Variables - example (cont.)

double Employee::annual_income() const
{
   return get_salary();
}
class Manager : public Employee
{
public:
   Manager(string n, double s, double b);
   virtual double annual_income() const;
private:
   double bonus;
};

21.2 Polymorphic Variables - example (cont.)

Manager::Manager(string n, double s, double b)
   : Employee(n, s), bonus(b) {}

double Manager::annual_income() const
{
   return get_salary() + bonus;
}

21.2 Polymorphic Variables (cont.)


21.2 Polymorphic Variables - Dynamic Binding


21.2 Polymorphic Variables - Dynamic Binding


21.2 Polymorphic Variables - Dynamic Binding (cont.)


21.3 Virtual and Nonvirtual Overriding


21.3 Virtual and Nonvirtual Overriding (cont.)


21.3 Virtual and Nonvirtual Overriding (cont.)


21.3 Virtual and Nonvirtual Overriding (cont.)


21.3 Virtual and Nonvirtual Overriding (cont.)


21.3 Virtual and Nonvirtual Overriding (cont.)


21.3 Virtual and Nonvirtual Overriding (cont.)

class Employee
{
   . . .
   virtual void print(ostream& out) const;
};

void Employee::print(ostream& out) const
{
   out << "Employee " << name();
}

21.3 Virtual and Nonvirtual Overriding (cont.)

class Manager : public Employee
{
   . . .
   virtual void print(ostream& out) const;
};

void Manager::print(ostream& out) const
{
   out << "Manager " << name();
}

ostream& operator<<(ostream& out, const Employee& e)
{
   e.print(out);
   return out;
}

21.3 Virtual and Nonvirtual Overriding (cont.)


21.3 Virtual and Nonvirtual Overriding - wrapup

Retain the virtual Keyword
Once declared virtual, a method remains virtual in all derived classes
Heterogeneous Collections
A vector of pointers can store values of any derived type
Include Virtual Destructors
If a class has a virtual method, define a virtual d'tor

21.4 Pure Virtual Member Functions


21.4 Pure Virtual Member Functions (cont.)

Syntax 21.1: Pure Virtual Member Function
class ClassName
{
   . . .
   virtual return_type function_name(parameters) = 0;
   . . .
};
Example:
class Shape
{
   . . .
   virtual double area() const = 0;
};

21.4 Pure Virtual Member Functions (cont.)

Syntax 21.1: Pure Virtual Member Function (cont.)
Purpose: Declare a member function with no definition. A class that contains at least one pure virtual function is termed abstract. Derived classes must either override the function and provide their own definition or they themselves will be considered abstract.

21.5 Obtaining Run-Time Typing Information (RTTI)

2 common ways to obtain the dynamic type of an object:

  1. dynamic cast - for casting down the inheritance hierarchy, checking for success
  2. Using the type_id operator to compare a dynamic type to a known type

Warning: use virtual methods instead of RTTI and complex conditionals


21.5 (cont.) RTTI - the Dynamic Cast

Syntax 21.2: Dynamic Cast
dynamic_cast<type_name>(expression)
Example:
Employee* e = new Manager("Sarah Smith", 67000, 2000);
Manager* m = dynamic_cast<Manager*>(e);
Purpose: Safely test the type of a polymorphic variable, converting to a derived class type if appropriate, returning a Null pointer if not.

21.5 (cont.) RTTI - the Dynamic Cast


21.5 (cont.) RTTI - the Dynamic Cast

for (int i = 0; i < department.size(); i++)
{
   Manager* m = dynamic_cast<Manager*>(department[i]);
      if (m != NULL)
         cout << "Employee " << department[i]->get_name()
            << " is a manager.\n";
   else
      cout << "Employee " << department[i]->get_name()
         << " is not a manager.\n";
}

21.5.1 The typeid Operator

Syntax 21.3: typeid
typeid(expression)
typeid(type_name)
Example:
#include <typeinfo>
typeid(*department[i]).name();
if (typeid(*department[i]) == typeid(Manager)) . . .
Purpose: Obtain dynamic type information from a polymorphic expression.

21.5.1 The typeid Operator (cont.)


21.5.1 The typeid Operator (cont.)


21.5.1 The typeid Operator (cont.)


21.6 Slicing and Polymorphism


21.7 Muliple Inheritance


21.7 Muliple Inheritance (cont.)


21.7 Muliple Inheritance (cont.)

Syntax 21.4: Multiple Inheritance
class DerivedClassName : public BaseClass1, . . . public BaseClassn
Example:
class TeachingAssistant : public Student, public Employee
{
   . . .
}
Purpose: Define a class that inherits features from two or more base classes.

21.7 Muliple Inheritance (cont.)


21.7 Muliple Inheritance (cont.)


21.7 Muliple Inheritance (cont.)


21.7.1 Name Ambiguity


21.7.1 Name Ambiguity (cont.)

  1. Use the fully qualified function name:
    cout << "Your teaching assistant is "
       << fred->Employee::get_id() << "\n";

21.7.1 Name Ambiguity (cont.)

  1. Redefine the ambiguous name in the new class:
    class TeachingAssistant : public Student, public Employee
    {
    public:
       string get_id() const;
       string student_id() const;
    };

21.7.1 Name Ambiguity (cont.)

// get_id will return Employee identification number
string TeachingAssistant::get_id()
{
   return Employee::get_id();
}

string TeachingAssistant::student_id()
	// Make student value available by a different name
{
   return Student::get_id();
}

21.7.2 Replicated Base Classes


21.7.2 Replicated Base Classes

class Employee : public Person
{
   . . .
};

class Student : public Person
{
   . . .
};

21.7.2 Replicated Base Classes (cont.)


21.7.2 Replicated Base Classes (cont.)


21.7.2 Replicated Base Classes (cont.)


21.7.2 Replicated Base Classes (cont.)


21.7.2 Replicated Base Classes (cont.)


21.8 Software Frameworks


21.8 Software Frameworks (cont.)


21.8 Software Frameworks (cont.)

Consider putting a window up on a screen. The concept of window is generic.


21.8 Software Frameworks (cont.)

class wxWindow
{
public:
   . . .
   // Pure virtual member function
   virtual void OnPaint(wxPaintEvent& event) = 0;
   virtual void OnMouseEvent(wxMouseEvent& event);
   . . .
};

void wxWindow::OnMouseEvent(wxMouseEvent& event)
{
   // Default behavior, do nothing
}

21.8 Software Frameworks (cont.)


21.8 Software Frameworks (cont.)

class ClockWindow : public wxWindow
   // ClockWindow will be developed in Chapter 27
{
public:
   . . .
   virtual void OnPaint(wxPaintEvent& event);
   virtual void OnMouseEvent(wxMouseEvent& event);
   . . .
};

void ClockWindow::OnMouseEvent(wxMouseEvent& event)
{
   . . . // Implement mouse events for this specific application
}

Chapter Summary


  1. Inheritance can be used to organize classes into hierarchies.
  2. Polymorphic variables are very powerful. Declared as one type, its static type, but can maintain a value of a different type, its dynamic type. Must be pointers or references.
  3. When a virtual method is called using a polymorphic variable, its dynamic type is used.
  4. A virtual method that is declared but not defined is called a pure virtual method. A class with a pure virtual method can not be instantiated. It is called an abstract class.

Chapter Summary (cont.)


  1. The dynamic type of a polymorphic variable can be tested using a dynamic cast, or the typeid operator.
  2. A class that inherits from two or more base classes is said to use multiple inheritance.
  3. A software framework (or toolkit) is a collection of classes and/or functions that capture the common features of a task. Methods are overridden to specialize behavior.