Polymorphism

Abstract

Runtime polymorphism in C++ is a challenging topic that is often not well understood by beginners, and indeed, by the authors of some C++ text books! This is a pity, as runtime polymorphism is without a doubt an essential component of any object oriented system. In fact some would use runtime polymorphism as a definition of OO. But others would not. The debate over the ``true'' definition of OO is an example of a holy war .

Introduction

In languages that are weakly typed, runtime polymorphism is very easy to understand. For example, in perl, if $a is an object reference of type Foo, it's pretty obvious that $a->f() is going to call the f method defined for class Foo, because perl references do not contain any type information besides the name of the package they belong to.

However, in strongly typed languages, it gets rather confusing, because types must be explicitly decided at compile time. Every object we declare contains type information, which must be available at compile time. But despite the apparent rigidity of strong typing, there is actually some room to move:

An Example

It should be clear that this enables us to randomly create different types of shapes, and the decision is truly deferred until runtime. We follow up with a complete example ( download )


#include <iostream>
#include <list>

class Shape
{
public:
    virtual void draw() = 0;
    virtual ~Shape() = 0;
protected:
    Shape(){}
    Shape(const Shape&){}
    Shape& operator=(const Shape&) { return *this; }
};

Shape::~Shape(){}

class Circle : public Shape 
{
public:
    virtual void draw() 
    {
        std::cout 
            <<  "           ****         \n"
            <<  "        *        *      \n"
            <<  "      *            *    \n"
            <<  "     *              *   \n"
            <<  "     *              *   \n"
            <<  "     *              *   \n"
            <<  "     *              *   \n"
            <<  "      *            *    \n"
            <<  "        *        *      \n"
            <<  "           ****         \n"
            << std:: endl;
    }
    virtual ~Circle(){}
};

class Triangle : public Shape
{
public:
    virtual void draw()
    {
        std::cout 
            <<  "     |\\               \n"
            <<  "     |+\\              \n"
            <<  "     |= \\             \n"
            <<  "     |= =\\            \n"
            <<  "     |== =\\           \n"
            <<  "     |== ==\\          \n"
            <<  "     |== ===\\         \n"
            <<  "     |==    =\\        \n"
            <<  "     |=  +++==\\       \n"
            <<  "     |=+  +====\\      \n"
            <<  "     |== +     =\\     \n"
            <<  "     |=+       ==\\    \n"
            <<  "     L____________\\   \n"
            << std:: endl;
    }
    virtual ~Triangle(){}
};

class Square: public Shape
{
public:
    virtual void draw()
    {
        std::cout 
            <<  "      ______________    \n"
            <<  "     |/             |   \n"
            <<  "     |//  ====      |   \n"
            <<  "     |///       ====|   \n"
            <<  "     |/////         |   \n"
            <<  "     |//===         |   \n"
            <<  "     |////========  |   \n"
            <<  "     |/========//   |   \n"
            <<  "     |//==/--       |   \n"
            <<  "     L______________J   \n"
            << std:: endl;
    }
    virtual ~Square(){}
};


int main()
{
    int choice = 0;
    Shape* s;
    std::list<Shape*> shapes;
    do {
        std::cout << "Pick a shape by entering a number from 1 to 3: \n"
            << "(1) Square\n" 
            << "(2) Triangle\n"
            << "(3) Circle\n" 
            << "(4) Quit" << std::endl;
        
        switch ( choice ) { 
            case 1: 
                s = new Square;
                break;
            case 2:
                s = new Triangle;
                break;
            case 3:
                s = new Circle;
                break;
            default:
                s = 0;
        } // switch

        if (s) shapes.push_back(s);
    }
    while ( std::cin >> choice && choice != 4 );

    std::list<Shape*>::const_iterator it;

    if ( ! shapes.empty() )
        for ( it = shapes.begin(); it != shapes.end(); ++it )
        {
            (*it)->draw();
            delete (*it);
        }

    return 0;


}