#include <iostream>
#include <cmath>
#include <string>

#define PI 3.14

using namespace std;

class Figure {  // polimorfic class, abstract class
  public:
//    virtual float area() const = 0;     // pure virtual, abstraction vs encapsulation/hermetization
    float area() const { return 0; }
    void info() { cout << "area of " << this->name << ": " << this->area() << endl; }
  protected:
    string name;            
};

class Circle: public Figure {
  public:
    Circle(float radius = 0) : radius(radius) { this->name = "Circle"; }
    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) { this->name = "Triangle"; }
    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) { this->name = "Rectangle"; }
    float area() const { return this->width * this->height; };
  protected:
    float width, height;
};

class Square: public Rectangle {
  public:
    Square(float side = 0) : Rectangle(side, side) { this->name = "Square"; }
// 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);
    
    f.info();
    c.info();
    t.info();
    r.info();
    s.info();
 
    Figure fr = Rectangle(4, 5);        
    cout << "fr: " << fr.area() << endl;
    fr.info();

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

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

    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;
}
