#include <iostream>
#include <cmath>

#define PI 3.14

using namespace std;

class Figure {
  public:
    float area() const;     // abstraction vs encapsulation/hermetization
};

class Circle: public Figure {
  public:
    Circle(float radius = 0) : radius(radius) {}
    float area() const;
  protected:
    float radius;
};

class Triangle: public Figure {
  public:
    Triangle(float base = 0, float height = 0) : base(base), height(height) {}
    float area() const;
  protected:
    float base, height;
};

class Rectangle: public Figure {
  public:
    Rectangle(float width = 0, float height = 0) : width(width), height(height) {}
    float area() const;
  protected:
    float width, height;
};

class Square: public Rectangle {
  public:
    Square(float side = 0) : Rectangle(side, side) {}
// code reusability - no need to implement method area()
};

float Figure::area() const {
    return 0;
}

float Circle::area() const {
    return PI * this->radius * this->radius;
}


float Triangle::area() const {
    return this->base * this->height / 2;
}


float Rectangle::area() const {
    return this->width * this->height;
}


int main() {
    Figure f;
    Circle c(1);
    Triangle t(2, 3);
    Rectangle r(2, 3);
    Square s(4);
    
    cout << f.area() << endl;
    cout << c.area() << endl;    
    cout << t.area() << endl;    
    cout << r.area() << endl;
    cout << s.area() << endl;
    
    Figure fr = Rectangle(4, 5);        
    cout << fr.area() << endl;

    Figure fs = Square(4);        
    cout << fs.area() << endl;

    Figure *pfr = new Rectangle(4, 5);        
    cout << pfr->area() << endl;
    cout << ((Rectangle*)pfr)->area() << endl;
    delete pfr;
    
    return 0;
}
