Problem bei eigener Rationalklasse
-
Morgen hier erstmal mal mein Code.
Fraction.h
#ifndef FRACTION_H_INCLUDED #define FRACTION_H_INCLUDED class Fraction { private: int zaehler; int nenner; public: Fraction(int z,int n); ///Konstruktor void operator+(Fraction fraction); void operator-(Fraction fraction); void operator*(Fraction fraction); friend std::ostream &operator<<(std::ostream &ostr, Fraction &f); ///Getter un Setter für zaehler int get_zaehler()const; void set_zaehler(int z); ///Getter und Setter für nenner int get_nenner()const; void set_nenner(int n); ///Methoden zum bearbeiten des "Bruches" void kuerzen(); int ggT(int a,int b); }; #endif // FRACTION_H_INCLUDEDFraction.cpp
#include <iostream> #include "Fraction.h" Fraction::Fraction(int z,int n) { zaehler = z; nenner = n; kuerzen(); } //////////////////////////////////////// int Fraction::get_zaehler()const { return zaehler; } void Fraction::set_zaehler(int z) { zaehler = z; } //////////////////////////////////////// int Fraction::get_nenner()const { return nenner; } void Fraction::set_nenner(int n) { nenner = n; } //////////////////////////////////////// int Fraction::ggT(int a,int b) { while(b != 0) { int temp = a%b; a = b; b = temp; } return a; } ///////////////////////////////////////// void Fraction::kuerzen() { int ggt = Fraction::ggT(Fraction::get_zaehler(),Fraction::get_nenner()); Fraction::set_zaehler(Fraction::get_zaehler() / ggt); Fraction::set_nenner(Fraction::get_nenner() / ggt); } ///////////////////////////////////////////// void Fraction::operator+(Fraction fraction) { fraction.set_zaehler(fraction.get_zaehler()*nenner); // Zähler des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler*fraction.get_nenner(); // Zähler des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren nenner = nenner *fraction.get_nenner(); // Nenner des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren fraction.set_nenner(fraction.get_nenner()*nenner); // Nenner des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler+fraction.get_zaehler(); // Addition der beiden neuen Zähler kuerzen(); } /////////////////////////////////////////////// void Fraction::operator-(Fraction fraction) { fraction.set_zaehler(fraction.get_zaehler() * nenner); // Zähler des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler * fraction.get_nenner(); // Zähler des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren nenner = nenner * fraction.get_nenner(); // Nenner des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren fraction.set_nenner(fraction.get_nenner() * nenner); // Nenner des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler-fraction.get_zaehler(); // Subtraktion der beiden neuen Zähler kuerzen(); } ////////////////////////////////////////////// void Fraction::operator*(Fraction fraction) { zaehler = zaehler * fraction.get_zaehler(); nenner = nenner * fraction.get_nenner(); kuerzen(); } ////////////////////////////////////////////// std::ostream &operator<<(std::ostream &ostr, Fraction &f) { return ostr<<f.get_zaehler()<<"/"<<f.get_nenner(); }Main.cpp
#include <iostream> #include "Fraction.h" using namespace std; int main() { Fraction fraction1(1,2); Fraction fraction2(3,2); fraction1+fraction2; cout<<fraction1<<endl; fraction1-fraction2; cout<<fracion1<<endl; }Ich bedanke mich jetzt schon mal bei allen, die es sich antuen, meinen code zu lesen.
Aber hier mein Problem.
Zurzeit verändere ich bei der Addition,Subtraktion,Multiplikation immer meine Original "Brüche". Das will ich aber nicht, weil wenn ich meinen Bruch zuerst Addiere und danach Subtrahieren will, rechne ich ja mit falschen Werten weiter. Wie kann ich es also schaffen, die Original, die ich meinem Konstruktor am anfang übergebe zu behalten und diese nicht zu verändern? Weil ich sonst ja nicht richtig weiterrechnen kann.EDIT: Bitte noch nicht so viel Kritisieren, das wollte ich machen lassen, wenn alles fertig ist

-
Du musst ein temporäres Bruch-Objekt in Deinen operator-Funktionen anlegen und das dann zurückgeben.
-
Und zusätzlich sollten die Operationen dann auch 'const' sein

-
Das sieht dann ungefähr so aus:
Fraction Fraction::operator*(Fraction const &rhs) const { Fraction result(zaehler*rhs.zaehler, nenner*rhs.nenner); result.kuerzen(); return result; }(Musst natürlich auch die Deklaration in der Klasse anpassen). Das const hinter dem Methodenkopf bedeutet, dass die Methode auch für konstante Objekte der Klasse aufgerufen werden kann, was ja sinnvoll ist, weil die Methode nichts an dem Original-Objekt ändert.
Normalerweise verwendet man für die interne Implementierung übrigens keine getter und setter Methoden, sondern greift (so wie da oben) direkt auf die Member zu... Ist im Endeffekt aber Geschmackssache.
Außerdem würde man für eine reale Implpementierung den operator*, +, /, etc. nicht als Methoden, sondern als Funktionen implementieren, denn wenn du z.B. eine automatische Konvertierung von int nach Fraction zulässt (mit einem einparametrigen Konstruktor), dann kann bei einer Methode ein Fraction mit einem int addiert werden, aber kein int mit einem Fraction...
Das ganze sähe dann so aus:
Fraction operator*(Fraction const &lhs, Fraction const &rhs) { Fraction result(lhs.get_zaehler()*rhs.get_zaehler(), lhs.get_nenner()*rhs.get_nenner()); result.kuerzen(); return result; }Jetzt muss man natürlich getter und setter verwenden, weil eine (globale) Funktion ja keinen Zugriff auf die Member hat, es sei denn du deklarierst sie als friend.
Das sollte alle Klarheiten beseitigt haben

Felix
-
ohh danke Felix, aber wie würde das bei meinem operator+ aussehen?
-
Firefighter schrieb:
ohh danke Felix, aber wie würde das bei meinem operator+ aussehen?
Genau so?
-
ja schon klar...nur er übergibt ja dem konstruktor in der operator* methode die werte der zaehler und nenner, aber beim operator+ muss ich die doch vorher noch überarbeiten, soll ich sie einfach am ende an den konstruktor übergeben oder wie jetzt?
-
Du könntest die Methoden auch so implementieren:
Fraction Fraction::operator*(Fraction const &rhs) const { Fraction result( *this ); result *= rhs; // Hier halt entsprechenden Operator return result; }So ist der Code der */+- Operatoren unabhängig von der Implementierung.
-
Firefighter schrieb:
ja schon klar...nur er übergibt ja dem konstruktor in der operator* methode die werte der zaehler und nenner, aber beim operator+ muss ich die doch vorher noch überarbeiten, soll ich sie einfach am ende an den konstruktor übergeben oder wie jetzt?
Jup, im Prinzip alles so machen wie vorher, bloß halt immer mit dem temporären Objekt und nicht mit dem Original.
-
Fraction Fraction::operator+(Fraction &fraction) { fraction.set_zaehler(fraction.get_zaehler()*nenner); // Zähler des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler*fraction.get_nenner(); // Zähler des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren nenner = nenner *fraction.get_nenner(); // Nenner des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren fraction.set_nenner(fraction.get_nenner()*nenner); // Nenner des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler+fraction.get_zaehler(); // Addition der beiden neuen Zähler Fraction result(zaehler,nenner); result.kuerzen(); std::cout<<result<<std::endl; return result; }würde das dann so richtig sein bei dem operator+? das ich ganz unten dann ein tempobjekt erzeuge und dort dann die neuen zaehler und nenner übergebe?? oder muss ich das anders machen?
-
Firefighter schrieb:
Fraction Fraction::operator+(Fraction &fraction) { fraction.set_zaehler(fraction.get_zaehler()*nenner); // Zähler des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler*fraction.get_nenner(); // Zähler des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren nenner = nenner *fraction.get_nenner(); // Nenner des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren fraction.set_nenner(fraction.get_nenner()*nenner); // Nenner des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren zaehler = zaehler+fraction.get_zaehler(); // Addition der beiden neuen Zähler Fraction result(zaehler,nenner); result.kuerzen(); std::cout<<result<<std::endl; return result; }würde das dann so richtig sein bei dem operator+? das ich ganz unten dann ein tempobjekt erzeuge und dort dann die neuen zaehler und nenner übergebe?? oder muss ich das anders machen?
Nein, das ist schlecht so. Du veränderst damit Deinen rechten Operanden, da er als Referenz übergeben wird. Du musst in der Funktion erst ein lokales, temporäres Fraction-Objekt anlegen. Und damit musst Du dann arbeiten.
Das Interface der Operator-Funktion würde ich so gestalten:Fraction operator+(const Fraction& right) const;Dann kannst Du keine der Fraction-Objekte ändern die nicht geändert weden dürfen, da der Compiler meckert.
-
sorry könnt ihr mir mal auf die srpünge helfen, ich habe es jetzt versucht umzuändern, jedoch mit liefert mir das ein falsches ergebnis...und so richtig durchblick hatte ich dann auch nicht mehr
Fraction Fraction::operator+(const Fraction &right)const { Fraction result(right.zaehler,right.nenner); result.zaehler = result.zaehler * right.nenner; // Zähler des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren result.zaehler = result.zaehler * result.nenner; // Zähler des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren result.nenner = result.nenner * right.nenner; // Nenner des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren result.nenner = result.nenner * result.nenner ; // Nenner des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren result.set_zaehler(result.get_zaehler()+result.get_zaehler()); // Addition der beiden neuen Zähler result.kuerzen(); std::cout<<result<<std::endl; return result; }wäre echt dankbar
-
Firefighter schrieb:
sorry könnt ihr mir mal auf die srpünge helfen, ich habe es jetzt versucht umzuändern, jedoch mit liefert mir das ein falsches ergebnis...und so richtig durchblick hatte ich dann auch nicht mehr
Fraction Fraction::operator+(const Fraction &right)const { Fraction result(right.zaehler,right.nenner); result.zaehler = result.zaehler * right.nenner; // Zähler des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren result.zaehler = result.zaehler * result.nenner; // Zähler des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren result.nenner = result.nenner * right.nenner; // Nenner des 1. Bruches mit dem Nenner des 2. Bruches multiplizieren result.nenner = result.nenner * result.nenner ; // Nenner des 2. Bruches mit dem Nenner des 1. Bruches multiplizieren result.set_zaehler(result.get_zaehler()+result.get_zaehler()); // Addition der beiden neuen Zähler result.kuerzen(); std::cout<<result<<std::endl; return result; }wäre echt dankbar
So in etwa:
Fraction Fraction::operator+(const Fraction &right)const { Faction result ( zaehler * right.nenner + right.zaehler * nenner , nenner * right.nenner ); return result; }
-
ja naklar....danke euch vielmals...wenn ich fertig bin, würde ich es hier gerne mal vorstellen um mich eurer Kritik anzunehmen
-
ich hätte aber noch eine frage, wie kann ich jetzt zum beispiel das ergebnis von
fraction1+fraction2 mit dem cout ausgeben lassen, zurzeit kommt immer ein fehler.
also es soll dann so aussehencout<<fraction<+fraction2<<endl;
-
Der Fehler kommt, weil der Operator << nicht für deine Bruch-Klasse überladen wurde. Du musst eben eine Methode schreiben, die den Zähler durch den Nenner dividiert und das Ergebnis als float oder double zurückgibt.
Noch zu den Operatoren: Wäre es nicht das einfachste, einfach globale Operatoren zu haben, wenn ja sowieso 2 Klassen benötigt werden? Und dass sie als friend deklariert wird, wäre ja auch kein Weltuntergang, oder?
Also etwa so:
Fraction operator+(const Fraction &right, const Fraction &left) { Fraction Result; // hier führst du die Operationen mit Result aus return Result; }
-
nee da haste was falsch verstanden, ich habe 1. nur eine Klasse und ich habe den << operator schon überladen,und außerdem will ich ja gar keine dezimalzahl am ende haben

hier meine überladung:std::ostream &operator<<(std::ostream &ostr, Fraction &f) { return ostr<<f.get_zaehler()<<"/"<<f.get_nenner(); }
-
Firefighter schrieb:
nee da haste was falsch verstanden, ich habe 1. nur eine Klasse und ich habe den << operator schon überladen,und außerdem will ich ja gar keine dezimalzahl am ende haben

hier meine überladung:std::ostream &operator<<(std::ostream &ostr, Fraction &f) { return ostr<<f.get_zaehler()<<"/"<<f.get_nenner(); }Also wenn Dein überladener <<-Operator ein Friend Deiner Fraction Klasse ist, kannst Du direkt auf die Zähler- und Nennervariablen Zugreifen. Also ohne setter und getter Methoden.
Außerdem sollte es so aussehen:std::ostream &operator<<(std::ostream &ostr, const Fraction &f)