Ziel dieses Übungsbeispiels ist es, Operator-Overloading und Exception-Handling in einem kurzen Programm zu implementieren.
### Aber um was geht es denn?
Es soll eine Klasse `Fraction`, die einen Bruch - also eine rationale Zahl - darstellt, erstellt werden. Nach fertiger Implementierung soll mit dieser Klasse wie mit gewöhnlichen `int` oder `double` mit den Operatoren `+`, `*`, `==` ... gerechnet werden können.
Beim Rechnen mit Brüchen ist außerdem zu beachten, dass der Nenner nie `0` werden darf. Insbesondere beim Erstellen eines neues Bruchs, aber auch beispielsweise beim Dividieren könnte es hier zu einem Problem kommen. Dafür soll eine eigene Exception `NullDivisionException` implementiert werden.
## Klasse Fraction
Die Klasse `Fraction` soll genau einen Bruch darstellen. Dafür werden zwei Attribute benötigt, nämlich ein Zähler (`nominator_`) und ein Nenner (`denominator_`).
Ein Bruch soll intern nach jeder Operation immer in gekürzter Form gespeichert sein und der Nenner soll immer positiv sein. Beispielsweise `5/-15` soll als `-1/3` gespeichert werden.
### Konstruktoren
Ein Bruch soll auf drei Arten erstellt werden können:
| Parameter | Beschreibung |
| --------- | ------------ |
| keiner | Der Bruch soll den Wert `0` besitzen. |
| `int` | Der Bruch soll den Wert der Ganzzahl besitzen. |
| `int`, `int` | Erster Paramter ist der Zähler, zweiter der Nenner. |
Im letzten Fall ist außerdem zu überprüfen, dass es zu keiner Division durch `0` kommt, ansonsten soll eine `NullDivisionException` geworfen werden. Außerdem ist zu beachten, dass der Bruch in oben beschriebenen Form gespeichert werden soll.
*Tipp: Es ist nicht notwendig drei unterschiedliche Konstruktoren zu erstellen. Wenn man es geschickt löst, kommt man mit einem aus.*
Copy-Konstruktor bzw. Copy-Assignment-Operator sollen als Übung explizit implementiert werden. Wichtig beim Copy-Assignment-Operator ist es, dass auch folgendes möglich sein soll: `b1 = b2 = b3`.
*Tipp: Überlege ob es hier auch zu einer Division durch `0` kommen kann bzw. ob der Bruch gekürzt werden muss.*
### Methoden
-`getNominator()`
- Getter für den Zähler
-`getDenominator()`
- Getter für den Nenner
-`value()`
- gibt den Wert des Bruchs als `double` zurück
-`reduce()`
- private Methode, um den Bruch zu kürzen und den Nenner positiv zu machen
*Tipp: Euklidischer Algorithmus. Ansonsten kann man auch alle möglichen Teiler durchprobieren, ist zwar nicht besonders effizient, aber gut genug für den Anfang.*
### Ausgabeoperator
Folgender Ausgabeoperator soll implementiert werden, `b1` ist ein Objekt der Klasse `Fraction`.
-`std::cout << b1`
-`b1` soll in der Form: `<nominator_> / <denominator_>` ausgegeben werden
### Arithmetische Operatoren
Folgende Operationen sollten auf jeden Fall implementiert werden, wobei der Copy-Assignment-Operator bereits implementiert sein sollte. `b1`, `b2`, `b3` sind Brüche, `a` ist ein `int`.
*Tipp: Manche Operatoren sind einfacher als Methode zu implementieren, andere wiederum müssen sogar unbedingt als Funktion implementiert werden.*
-`b1 = b2 + b3`
-`b2` und `b3` werden zusammenaddiert, ändern sich aber nicht
-`b1 = b2 + a`
-`b2` und `a` werden zusammenaddiert, ändern sich aber nicht (`a` ist ein `int`!)
-`b1 = a + b3`
-`a` und `b3` werden zusammenaddiert, ändern sich aber nicht (`a` ist ein `int`!)
-`b1 = b2 += b3`
-`b3` wird direkt auf `b2` addiert
- das Ergebnis kann an `b1` zugewiesen werden
-`b1 = b2++`
- post-increment
- in `b1` wird der alte Wert von `b2` geschrieben
- anschließend wird `b2` um den Wert `1` erhöht
-`b1 = ++b2`
- pre-increment
-`b2` wird um den Wert `1` erhöht
- das Ergebnis wird in `b1` geschrieben
-`b1 = -b2`
-`b1` wird das Negative von `b2` zugewiesen
-`b2` bleibt unverändert
-`b1 = ~b2` (bitweiser Operator)
-`b1` wird der Kehrwert von `b2` zugewiesen
- der Nenner soll weiterhin positiv sein
-`NullDivisionException` falls der Nenner `0` ist
-`b2` bleibt unverändert
Alle weiteren arithmetischen Operatoren, wie beispielsweise `-`, `-=`, `--`, `*`, `/`... können analog implementiert werden.
### Logische Operatoren und Vergleichsoperatoren
Folgende Operatoren sollten auf jeden Fall implementiert werden. `b1`, `b2` sind wiederum Brüche.
-`b1`
- ist genau dann `false` sein, wenn der Bruch den Wert `0` besitzt
-**Wichtig! `int a = b1;` darf nicht gültig sein bzw. kompilieren. Daher ist das Schlüsselwort `explicit` zu verwenden.**
-`!b1`
- ist genau dann `true` sein, wenn der Bruch den Wert `0` besitzt
-`b1 == b2`
- ist genau dann `true`, falls `b1` und `b2` denselben Wert besitzen
-`b1 != b2`
- ist genau dann `true`, falls `b1` und `b2` verschiedene Werte besitzen
-`b1 < b2`
- ist genau dann `true`, falls `b1` echt kleiner als `b2` ist
-`b1 <= b2`
- ist genau dann `true`, falls `b1 < b2` oder `b1 == b2`
Alle weiteren Vergleichsoperatoren können analog implementiert werden.
## Klasse NullDivisionException
Diese Klasse stellt eine Exception dar und soll eine Fehlermeldung repräsentieren, wenn in einem Bruch der Nenner `0` werden würde. Daher soll diese Klasse auch von `std::exception` abgeleitet werden. Innerhalb der Klasse soll es genau ein Attribut gegeben, nämlich die Fehlermeldung `message_`, als `std::string`.
### Konstruktor
Weiters soll es genau einen Konstruktor geben, der als einzigen Parameter den Zähler des fehlerhaften Bruchs übergibt bekommt. Anschließend soll in `message_` die Fehlermeldung ```<nominator> / 0 - Dividing through 0 not valid!\n```, wobei `<nominator>` durch den übergebenen Parameter ersetzt werden soll. Der Copy-Konstruktor und der Copy-Assignment-Operator sollen gelöscht werden.
### Methoden
Außerdem soll in der Klasse genau eine Methode implementiert werden, nämlich die `what()`-Methode aus der Basisklasse. Diese Methode liefert als Rückgabewert einen `const char*`, ist selbst `const`, darf selbst keine Exception werfen (`noexcept`) und überschreibt die Methode aus der Basisklasse (`override`). Hier soll genau die `message_` zurückgegeben werden, aber als eben als `const char*`, nicht als `std::string`.
## Testprogramm
Ein kurzes Testprogramm, dass die wesentlichen Funktionalitäten überprüft steht bereits zur Verfügung. Die noch offenen Testcases werden in Kürze noch folgen.