// geomFig.cpp
#include <iostream>
using namespace std;


class Shape {
  double x, y;
public:
  Shape(double x, double y) {
    setX(x);
    setY(y);
    cout << "Shape() called" << endl;
  }

  virtual ~Shape() = 0;

  double getX() const  { return x; }
  double getY() const  { return y; }
  void setX(double xx) { x = xx; }
  void setY(double yy) { y = yy; }

  void move(double dx, double dy) {
    x += dx;
    y += dy;
  }

  virtual void print() const {
  	cout << '(' << x << ", " << y << ')';
  }
};

Shape::~Shape() { cout << "~Shape() called" << endl; }


class Circle : public Shape {
  double radius;
public:
  Circle(double x, double y, double r);

  ~Circle()  { cout << "~Circle() called" << endl; }

  double getRadius() const { return radius; }

  bool setRadius(double r) {
    if (r >= 0) {
      radius = r;
      return true;
    }
    else return false;
  }

  void print() const;
};


// AUFGABE 2.a
// Korrigieren Sie die Definition des untenstehenden Circle-Konstruktors:
//   inline Circle::Circle(double x, double y, double r)
//   : x(xx), y(yy), radius(r) { }

// Korrekte Definition des Circle-Konstruktors:
inline Circle::Circle(double x, double y, double r)
: Shape(x, y), radius(r) {
  cout << "Circle() called" << endl;
}


// AUFGABE 2.b
// Schreiben Sie die fehlende Definition der Funktion print() der Klasse Circle.
// Die Funktion gibt den Mittelpunkt und den Radius eines Circle aus.
inline void Circle::print() const {
  cout <<         "Circle: Mittelpunkt: ";
  Shape::print();
  cout << endl << "        Radius: " << radius << endl;
}

// Leiten Sie von der Klasse Shape die Klasse Rectangle und von dieser die
// Klasse Square ab. Der Konstruktor fuer Rectangle erhalte als Argumente den
// Koordinatenbezugspunkt (origin) in der linken oberen Ecke (positive x-Achse
// nach rechts, positive y-Achse nach unten) sowie Hoehe und Breite. Nutzen Sie
// geerbte Instanzvariablen.
// Definieren Sie einen angepassten Konstruktor fuer Square.
// Definieren Sie fuer beide Klassen eine print-Funktion.
class Rectangle : public Shape {
   double height, width;
public:
  Rectangle(double x, double y, double h, double w)
  : Shape(x,y), height(h), width(w) {
    cout << "Rectangle() called" << endl;
  }

  ~Rectangle()  { cout << "~Rectangle() called" << endl; }

   double getHeight() const { return height; }

   void print() const {
     cout <<         "Rectangle: Ursprung: ";
     Shape::print();
     cout << endl << "           Hoehe: " << height << ", Breite: " << width << endl;
  }
};


class Square : public Rectangle {
 public:
   Square( double x, double y, double side) : Rectangle(x, y, side, side) {
    cout << "Square() called" << endl;
  }

  ~Square()  { cout << "~Square() called" << endl; }

   void print() const {
     cout <<         "Square: Ursprung: ";
     Shape::print();
     cout << endl << "        Seite: " << Rectangle::getHeight() << endl;
  }
};


// Realisieren Sie ein main mit einem Array, das drei Zeiger auf Shapes auf-
// weist. Die Zeiger sollen auf einen Circle, einen Rectangle und einen Square
// zeigen, die alle auf dem Heap angelegt wurden.
// Iterieren Sie ueber das Array und senden Sie via Zeiger die Funktion print
// an die Shapes (ohne cast!). Nehmen Sie ggf. noetige Aenderungen an print vor.
// Zerstoeren Sie am Schluss alle Objekte vom hoechsten zum niedrigsten Index.
// Nehmen Sie auch hier noetige Ergaenzungen in den Klassen vor.
int main() {
	Shape *shapes[] = {
		new Circle(1, 2, 10), new Rectangle(10, 10, 2, 6), new Square(3, 3, 7)
	};
	cout << endl;

	for (int i = 0; i < sizeof shapes / sizeof(Shape *); ++i) {
		shapes[i]->print();
		cout << endl;
	}

	for (int i = sizeof shapes / sizeof(Shape *) - 1; i >= 0 ; --i) {
		delete(shapes[i]);
		shapes[i] = 0;
	}
	system("pause");
}
