Virtual Functions:
Polymorphism allows two or more objects in an inheritance hierarchy 
                   to have identical member functions that perform distinct tasks
C++ implements polymorphism by using dynamic binding of virtual member functions
                        This contrasts with static binding, which is the usual way of linking an object with a member function. 
Polymorphism
    - object-oriented programming is refer to as "inheritance with runtime polymorphism." 
    - allows two or more objects in an inheritance hierarchy to have operations with the same prototype that perform distinct tasks. 
    - when calls by using a pointer or reference to an object, the runtime system determines the required version
       This is known as dynamic binding and contrasts with static binding, 
             in which the compiler determines which function should be called. 
    - implemented by declaring functions using virtual

Pure Virtual Functions and Abstract Classes
    -  A pure virtual function declared in a base class forces the definition of the function in a derived class.
    -  The base class is known as an abstract class; it is a template or a mold for the construction of derived classes. 
    -  An abstract base class is used to specify the design of a class that is likely to have different implementations.



Pointers To Derived Classes:
    A pointer declared as a pointer to a base class can also be used to point to any class derived from that base.
Although you can use a base pointer to point to a derived object, you can access only those members of the derived object that were inherited from the base.
   Example:
#include <iostream>
using namespace std;

class base {
 int x;
public:
 void setx(int i) { x = i; }
 int getx() { return x; }
};

class derived : public base {
 int y;
public:
 void sety(int i) { y = i; }
 int gety() { return y; }
};

void main()
{
 base *p;
 base b_ob;
 derived d_ob;

 // use p to access base object
 p = &b_ob;
 p->setx(10);
 cout << "Base object x: " << p->getx() << '\n';

 // use p to access derived object
 p = &d_ob;
 p->setx(99);

 //can't use p to set y, so do it directly
 d_ob.sety(88);
 cout << "Derived object x: " << p->getx() <<'\n';
 cout << "Derived object y: " << d_ob.gety() << '\n';
}

Introduction to Virtual Functions:
Defintion: A virtual function is a member function that is declared within a base class and redefined by a derived class.
Methods:   1. To create a virtual function, precede the function's declaration in base class with the keyword virtual.
                  2. When a virtual function is redefined by a derived class, the keyword virtual is not needed.
Polymorphism Philosophy:  One interface, multiple methods.
Run-Time Polymorphism:  Which version of the virtual function to be executed is made at run time.
Example:
#include <iostream>
using namespace std;

class base {
public:
 int i;
 base(int x)  { i = x; }
 virtual void func()
 {
  cout << "Using base version of func(): ";
  cout << i <<'\n';
 }
};

class derived1 : public base {
public:
 derived1(int x) : base(x) {}
 void func()
 {
  cout << "Using derived1's version of func(): ";
  cout << i*i << '\n';
 }
};

class derived2 : public base {
public:
 derived2(int x) : base(x) {}
 void func()
 {
  cout << "Using derived2's version of func(): ";
  cout << i+i << '\n';
 }
};

void main()
{
 base *p;
 base b_ob(10);
 derived1 d_ob1(10);
 derived2 d_ob2(10);

 p = &b_ob;
 p->func();   //use base's func()

 p = &d_ob1;
 p->func();   //use derived1's func()

 p = &d_ob2;
 p->func();   //use derived2's func()
}

Output:
Using base version of func(): 10
Using derived1's version of func(): 100
Using derived2's version of func(): 20
Difference from function overload:   
  • Function overload must differ in type and/or number of parameters.
  • Virtual function has the same type and number of parameters and it must be a class member.:
Pure Virtual Function:
     When a virtual function is made pure, it forces any derived class to override it.
     General Form:
          virtual type func-name( parameter-list ) = 0;
      When a class contains at least one pure virtual function, it is referred to as an abtract class.
     No objects of that class can be created.  It exits only to be inherited.
Example:
#include <iostream>
using namespace std;

class area {
    double dim1, dim2;   // dimensions of figure
public:
 void setarea(double d1, double d2)
 {
  dim1 = d1;
  dim2 = d2;
 }
 void getdim(double &d1, double &d2)
 {
  d1 = dim1;
  d2 = dim2;
 }
 virtual double getarea() = 0; //pure virtual function
};

class rectangle : public area {
public:
 double getarea()
 {
  double d1, d2;

  getdim(d1, d2);
  return d1 * d2;
 }
};

class triangle : public area {
public:
 double getarea()
 {
  double d1, d2;

  getdim(d1, d2);
  return 0.5 * d1 * d2;
 }
};
 

void main()
{
 area *p;
 rectangle r;
 triangle t;

 r.setarea(3.3, 4.5);
 t.setarea(4.0, 5.0);

 p = &r;
 cout << "Rectangle has area: " << p->getarea() <<'\n';

 p = &t;
 cout << "Triangle has area: " << p->getarea() <<'\n';
}