// Polymorphism
//
// Deborah R. Fowler
// Date: October 20, 2019
//
// Simple example of the elegance of polymorphism

#include <iostream>
using namespace std;

class Phone
{
    public:
        float cost;
        // virtual void ring()
        // To make an abstract class we set this to zero
        virtual void ring() = 0;
};

void Phone::ring()
{
    cout << "\n PHONE Brrring, Brring, Brring ";
}

class Mobile : public Phone
{
    public:
        void ring();
};

void Mobile::ring()
{
    cout << "\n MOBILE Beep, Beep";
}

class Landline : public Phone
{
    public:
        void ring();    
};

void Landline::ring()
{
    cout << "\n LANDLINE Booooppp, Booooooppp, Booooooopppp, Booooopppppp";
}

void showPoly(Phone* pptr);

int main()
{
    // Phone *pPhone = new Phone;
    Mobile *pMobile = new Mobile;
    Landline *pLandline = new Landline;
    // Brute force would be
    // pPhone->ring();
    pMobile->ring();
    pLandline->ring();
    
    cout << "\n\nA more elegant way - polymorphism";
    
    // However what if we declared our two phones in terms of the base class?
    Phone *pAnotherMobile = new Mobile;
    Phone *pAnotherLand = new Landline;
    // and we were to use only this pointer to determine the ring
    showPoly(pAnotherMobile);
    showPoly(pAnotherLand);
}

// Shows that the proper ring is determined solely on the pointer type
// We simply call ring and let the code figure out which to use based on the pointer
void showPoly(Phone* pptr)
{
    pptr->ring();
}
