#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <string>
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 : public vector<T> {
public:
void add(T const& val) {
this->push_back(val);
}
template<typename F>
void for_each(F f) {
for(auto& obj : *this) {
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);
}
class Motor : public Integer {
public:
Motor(int ps) : Integer(ps) {}
FORWARD_ASSIGN(Motor, Integer)
};
//eigentlich : public Boolean, aber ich bin zu faul einen bool zu implementeiren
template<typename Position>
class Tuere : public Integer, public Position {
public:
Tuere(int isOpen=0) : Integer(isOpen) {}
FORWARD_ASSIGN(Tuere, Integer)
};
class Position : public string {
public:
FORWARD_ASSIGN(Position, string)
};
class LinksHinten : public Position {
public:
LinksHinten() : Position("LinksHinten") {}
FORWARD_ASSIGN(LinksHinten, Position)
};
class LinksVorne : public Position {
public:
LinksVorne() : Position("LinksVorne") {}
FORWARD_ASSIGN(LinksVorne, Position)
};
class RechtsHinten : public Position {
public:
RechtsHinten() : Position("RechtsHinten") {}
FORWARD_ASSIGN(RechtsHinten, Position)
};
class RechtsVorne : public Position {
public:
RechtsVorne() : Position("RechtsVorne") {}
FORWARD_ASSIGN(RechtsVorne, Position)
};
class Fuellstand : public ChangeObservableArithmeticType<PositiveInteger> {
public:
FORWARD_ASSIGN(Fuellstand, ChangeObservableArithmeticType)
operator ChangeObservableArithmeticType() const {
return *this;
}
FORWARD_ARITHMETIC_OPS(Fuellstand, ChangeObservableArithmeticType)
};
class Maximalstand : public PositiveInteger {
public:
FORWARD_ASSIGN(Maximalstand, PositiveInteger)
};
class Tank : private Maximalstand, private Fuellstand {
public:
Tank(int liter) : Maximalstand(liter), Fuellstand(liter) {
Fuellstand::add([&](::PositiveInteger const&, ::PositiveInteger const& newVal) {
if(newVal.operator ::Integer().value > Maximalstand::operator ::Integer().value)
throw "zu hoher Fuellstand";
});
}
bool isVoll() const { return Maximalstand::operator ::Integer().value == Fuellstand::value; }
operator Fuellstand() const {
return *this;
}
FORWARD_ARITHMETIC_OPS(Tank, Fuellstand)
};
class Geschwindigkeit : public Integer {
public:
Geschwindigkeit(int kmh) : Integer(kmh) {}
FORWARD_ASSIGN(Geschwindigkeit, Integer)
};
class Name : public string {
public:
FORWARD_ASSIGN(Name, string)
};
class Auto
: public Motor
, public Tuere<LinksHinten>, public Tuere<LinksVorne>, public Tuere<RechtsHinten>, public Tuere<RechtsVorne>
, protected Geschwindigkeit, protected Tank, public Name {
public:
Auto(Name const& name, Tank const& tank) : Tank(tank), Name(name), Geschwindigkeit(0) {}
void gasgeben() {
Geschwindigkeit::operator+=(10);
}
void bremsen() {
Geschwindigkeit::operator -=(10);
}
void tick() {
//10kmh kosten 1 liter pro tick
PositiveInteger kosten = Geschwindigkeit::value/10;
Tank::operator-=(kosten);
}
operator Geschwindigkeit() {
return *this;
}
};
int main() {
Auto merzedes;
merzedes.Motor::operator=(100); //set PS
merzedes.gasgeben();
merzedes.gasgeben();
merzedes.tick();
return 0;
}
void rumspielen() {
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));
}