#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;
#define FORWARD_ASSIGN(from, to) \
from(to const& other) : to(other) {} \
from const& operator=(from const& other) { to::operator=(other); return *this; }
#define FORWARD_ARITHMETIC_OPS(from, to) \
from& operator+=(from const& other) { \
to::operator+=(other); return *this; \
} \
from& operator-=(from const& other) { \
to::operator-=(other); return *this; \
} \
from& operator*=(from const& other) { \
to::operator*=(other); return *this; \
} \
from& operator/=(from const& other) { \
to::operator/=(other); return *this; \
} \
friend from operator+(from const& lhs, from const& rhs) { \
return operator+(lhs.operator to(), rhs.operator to()); \
} \
friend from operator-(from const& lhs, from const& rhs) { \
return operator-(lhs.operator to(), rhs.operator to()); \
} \
friend from operator*(from const& lhs, from const& rhs) { \
return operator*(lhs.operator to(), rhs.operator to()); \
} \
friend from operator/(from const& lhs, from const& rhs) { \
return operator/(lhs.operator to(), rhs.operator to()); \
}
//folgendes wäre Teil der Standardlibrary
//nur minimale features implementiert (zeitgründe)
class Integer {
public:
typedef int BaseType;
int value;
Integer(int value=0) : value(value) {}
Integer(Integer const& other) : value(other.value) {}
Integer& operator=(Integer const& other) {
value=other.value;
return *this;
}
Integer& operator+=(Integer const& other) {
value+=other.value;
return *this;
}
Integer& operator-=(Integer const& other) {
value-=other.value;
return *this;
}
Integer& operator*=(Integer const& other) {
value*=other.value;
return *this;
}
Integer& operator/=(Integer const& other) {
value/=other.value;
return *this;
}
};
Integer operator+(Integer const& lhs, Integer const& rhs) {
return Integer(lhs.value+rhs.value);
}
Integer operator-(Integer const& lhs, Integer const& rhs) {
return Integer(lhs.value-rhs.value);
}
Integer operator*(Integer const& lhs, Integer const& rhs) {
return Integer(lhs.value*rhs.value);
}
Integer operator/(Integer const& lhs, Integer const& rhs) {
return Integer(lhs.value/rhs.value);
}
class PositiveInteger : protected Integer {
public:
typedef int BaseType;
PositiveInteger(int value=0) : Integer(value) { if(value<0) throw "Negative Value"; }
PositiveInteger(Integer const& other) : Integer(other) { if(value<0) throw "Negative Value"; }
PositiveInteger& operator=(Integer const& other) {
if(other.value < 0) throw "Negative Value";
value=other.value;
return *this;
}
operator Integer() const { return *this; }
FORWARD_ARITHMETIC_OPS(PositiveInteger, Integer)
};
template<typename T>
class Vector {
private:
vector<T> impl;
public:
void add(T const& val) {
impl.push_back(val);
}
template<typename F>
void for_each(F f) {
for(auto& obj : impl) {
f(obj);
}
}
};
template<typename T>
class ChangeObserver : public Vector<function<void(T const&, T const&)> > {
public:
void change(T const& oldVal, T const& newVal) {
this->for_each([&](function<void(T const&, T const&)> f) { f(oldVal, newVal); });
}
};
template<typename ValueType>
class ChangeObservableArithmeticType : protected ValueType, public ChangeObserver<ValueType> {
public:
typedef typename ValueType::BaseType BaseType;
ChangeObservableArithmeticType(typename ValueType::BaseType value=0) : ValueType(value) {}
ChangeObservableArithmeticType(ChangeObservableArithmeticType const& other) : ValueType(other) {}
ChangeObservableArithmeticType(ValueType const& other) : ValueType(other) {}
ChangeObservableArithmeticType& operator=(ChangeObservableArithmeticType const& other) {
this->change(*this, other);
this->value=other.value;
return *this;
}
operator ValueType() const {
return *this;
}
FORWARD_ARITHMETIC_OPS(ChangeObservableArithmeticType, ValueType)
};
class Radius : public ChangeObservableArithmeticType<PositiveInteger> {
public:
Radius() {}
Radius(ChangeObservableArithmeticType::BaseType value) : ChangeObservableArithmeticType(value) {}
PositiveInteger const& asPositiveInteger() const {
return *this;
}
FORWARD_ASSIGN(Radius, ChangeObservableArithmeticType)
};
class Punkt : public Integer {
public:
FORWARD_ASSIGN(Punkt, Integer)
Punkt(int val) : Integer(val) {}
};
class PunktX : public Punkt { public: FORWARD_ASSIGN(PunktX, Punkt) PunktX(int val):Punkt(val){} };
class PunktY : public Punkt { public: FORWARD_ASSIGN(PunktY, Punkt) PunktY(int val):Punkt(val){} };
class PunktXY : public PunktX, public PunktY {
public:
PunktXY(int x=0, int y=0) : PunktX(x), PunktY(y) {}
};
class Startpunkt : public PunktXY { public: FORWARD_ASSIGN(Startpunkt, PunktXY) };
class Endpunkt : public PunktXY { public: FORWARD_ASSIGN(Endpunkt, PunktXY) };
class Kreis : public Radius, public PunktXY {
public:
Kreis(int r) : Radius(r) {
Radius::add([&](::PositiveInteger const&, ::PositiveInteger const&) {
redraw();
});
redraw();
}
void redraw() {
cout<<"Radius changed, Kreis redrawn\n";
}
};
class Laenge : public Integer { public: FORWARD_ASSIGN(Laenge, Integer) };
class Strecke : public Startpunkt, public Endpunkt {
public:
Strecke() : Startpunkt(PunktXY(0,0)), Endpunkt(PunktXY(0,0)) {}
};
class Rechteck : public PunktXY, public Laenge {
public:
Rechteck(int laenge) : Laenge(laenge) {}
};
void verdoppleRadius(Radius& r) {
r=r*2;
}
void printKoordinaten(PunktXY const& p) {
cout<<"("<<p.PunktX::value<<"/"<<p.PunktY::value<<")\n";
}
void wierdShit(Kreis& k, Laenge& l) {
l=l*static_cast<PunktX&>(k)+static_cast<PunktY&>(k);
}
int main() {
Kreis k(3);
Rechteck r(12);
Strecke s;
k.PunktXY::operator=(PunktXY(10,20));
r.PunktXY::operator=(PunktXY(1,2));
s.Startpunkt::operator=(PunktXY(5,7));
s.Endpunkt::operator=(PunktXY(15,17));
//2x redraw ausführen:
k.Radius::operator=(7);
try {
//force error
k.Radius::operator=(-7);
} catch(...) {
cout<<"Error\n";
}
verdoppleRadius(k);
printKoordinaten(k);
printKoordinaten(r);
printKoordinaten(static_cast<Startpunkt&>(s));
return 0;
}