/// @file   main.cpp
/// @author Jens Gruschel
/// @date   2016-07-14
/// Vererbung und Polymorphismus

#include <iostream>
#include <cmath>

using std::cout;
using std::endl;

// unbenannter Namespace
// (damit ist folgendes nur in dieser Datei gueltig)
namespace {
    const double pi = acos(-1.0);
}

/// Basisklasse bzw. Interface fuer geometrische Formen
class Shape
{
public:
    virtual ~Shape() {}
    virtual double getArea() const = 0;
    virtual double getCircumference() const = 0;
};

/// ein Quadrat ist eine geometrische Form
class Square : public Shape
{
public:
    explicit Square(const double length);
    double getArea() const override;
    double getCircumference() const override;
private:
    double length;
};

Square::Square(const double length) : length(length)
{
}

double Square::getArea() const
{
    return length * length;
}

double Square::getCircumference() const
{
    return 4.0 * length;
}

/// ein Kreis ist ebenfalls eine geometrische Form
class Circle : public Shape
{
public:
    explicit Circle(const double diameter);
    double getArea() const override;
    double getCircumference() const override;
private:
    double radius;
};

Circle::Circle(const double diameter) : radius(0.5 * diameter)
{
}

double Circle::getArea() const
{
    return pi * radius * radius;
}

double Circle::getCircumference() const
{
    return pi * 2.0 * radius;
}

/// Funktion, die geometrische Form verwendet
/// (ohne zu wissen welche)
void printInfo(Shape& shape)
{
    cout << "Flaecheninhalt: " << shape.getArea() << endl;
    cout << "Umfang:         " << shape.getCircumference() << endl;
}

int main()
{
    // Quadtrat mit Kantenlaenge 3
    Square square(3.0);
    printInfo(square);

    // Kreis mit Durchmesser 3
    Circle circle(3.0);
    printInfo(circle);

    return 0;
}