#include <iostream>
#include <cmath>

#define PI 3.14

using namespace std;

class Figure {  // abstract class
  public:
//    virtual float area() const = 0;     // pure virtual, abstraction vs encapsulation/hermetization
    virtual float area() const { return 0; }
};

class Circle: public Figure {
  public:
    Circle(float radius = 0) : radius(radius) {}
    float area() const { return PI * this->radius * this->radius; };
  protected:
    float radius;
};

class Triangle: public Figure {
  public:
    Triangle(float base = 0, float height = 0) : base(base), height(height) {}
    float area() const { return this->base * this->height / 2; };
  protected:
    float base, height;
};

class Rectangle: public Figure {
  public:
    Rectangle(float width = 0, float height = 0) : width(width), height(height) {}
    float area() const { return this->width * this->height; };
  protected:
    float width, height;
};

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


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

    Figure *pfr = &r;        
    cout << "pfr: " << pfr->area() << endl;
    cout << "(Rectangle*)pfr" << ((Rectangle*)pfr)->area() << endl;

    Figure &rfr = s;
    cout << "rfr: "<<  rfr.area() << endl;

    Figure figures[4] = { c, t, r, s };
//    Figure *figures[4] = { &c, &t, &r, &s };
//    Figure *figures[4] = { new Circle(1), new Triangle(2, 3), new Rectangle(2, 3), new Square(4) };

    for (int i = 0; i < 4; i++) {
        cout << "figures[" << i << "]: " << figures[i].area() << endl;  // static vs dynamic type
    }

//    for (int i = 0; i < 4; i++) {
//        delete figures[i];
//    }
    
    return 0;
}
