Vorstellung Fraction Klasse



  • Morgen,

    ich würde euch gerne meine Fraction Klasse vorstellen(zumindest das was ich selbst geschafft habe). Ich bitte euch darum, um Konstruktive Kritik mit Erklärung zu dem was es zu kritisieren gibt und mir noch Verbesserungsvorschläge vorschlagt. Außerdem bitte ich um Erklärung von Erweiterungen wenn ihr welche machen würdet. Weiterhin wollte ich fragen was ich alles ändern müsste oder ob es überhaupt Sinn macht wenn ich das ganze als Template machen.

    Fraction.h

    #ifndef FRACTION_H_INCLUDED
    #define FRACTION_H_INCLUDED
        class Fraction
        {
            private:
                    int zaehler;
                    int nenner;
            public:
    
            ///Konstruktor
            Fraction(int z,int n);
            Fraction() {}
            ///Überladene Operatoren
            Fraction operator+(const Fraction &right)const;
            Fraction operator+(const float right)const;
            Fraction operator-(const Fraction &right)const;
            Fraction operator-(const float right)const;
            Fraction operator*(const Fraction &fraction)const;
            Fraction operator*(const float fraction)const;
            Fraction operator/(const Fraction &right)const;
            Fraction operator/(const float right)const;
            ///Ende Überladene Operatoren
            friend std::ostream &operator<<(std::ostream &ostr, const Fraction &f);
            friend std::istream &operator>>(std::istream &inside,Fraction &f);
            ///Getter und 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_INCLUDED
    

    Fraction.cpp

    #include "includes.h"
    
    Fraction::Fraction(int z,int n)
    {
        Fraction::zaehler = z;
        Fraction::nenner = n;
    
        Fraction::kuerzen();
    }
    ////////////////////////////////////////
    int Fraction::get_zaehler()const
    {
        return Fraction::zaehler;
    }
    void Fraction::set_zaehler(int z)
    {
        Fraction::zaehler = z;
    }
    ////////////////////////////////////////
    int Fraction::get_nenner()const
    {
        return Fraction::nenner;
    }
    void Fraction::set_nenner(int n)
    {
        Fraction::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 = ggT(zaehler,nenner);
    
        zaehler = zaehler / ggt;
        nenner = nenner / ggt;
    
    }
    
    /////////////////////////////////////////////
    Fraction Fraction::operator+(const Fraction &right)const
    {
        Fraction result( zaehler * right.nenner + right.zaehler * nenner, nenner * right.nenner );
    
        result.kuerzen();
        return result;
    }
    /////////////////////////////////////////////
    Fraction Fraction::operator+(const float right)const
    {
        Fraction result( zaehler * right + right * nenner, nenner * right );
    
        result.kuerzen();
        return result;
    }
    ///////////////////////////////////////////////
    Fraction Fraction::operator-(const Fraction &right)const
    {
        Fraction result( zaehler * right.nenner - right.zaehler * nenner, nenner * right.nenner );
    
        result.kuerzen();
        return result;
    }
    ///////////////////////////////////////////////
    Fraction Fraction::operator-(const float right)const
    {
        Fraction result( zaehler * right - right * nenner, nenner * right );
    
        result.kuerzen();
        return result;
    }
    //////////////////////////////////////////////
    Fraction Fraction::operator*(const Fraction &fraction) const
    {
        Fraction result(zaehler*fraction.zaehler, nenner*fraction.nenner);
        result.kuerzen();
        return result;
    }
    //////////////////////////////////////////////
    Fraction Fraction::operator*(const float fraction) const
    {
        Fraction result(zaehler*fraction, nenner*fraction);
        result.kuerzen();
        return result;
    }
    //////////////////////////////////////////////
    Fraction Fraction::operator/(const Fraction &right) const
    {
        Fraction result(zaehler*right.nenner, nenner*right.zaehler);
        result.kuerzen();
        return result;
    }
    //////////////////////////////////////////////
    Fraction Fraction::operator/(const float right) const
    {
        Fraction result(zaehler*right, nenner*right);
        result.kuerzen();
        return result;
    }
    //////////////////////////////////////////////
    std::ostream &operator<<(std::ostream &ostr, const Fraction &f)
    {
        return ostr<<f.zaehler<<"/"<<f.nenner;
    }
    //////////////////////////////////////////////
    std::istream &operator>>(std::istream &inside,Fraction &f)
    {
        std::string bruch;
        std::string str_nenner;
        std::string str_zaehler;
        std::stringstream string_to_int;
        int gefunden;
        int neuerzaehler;
        int neuernenner;
    
        inside>>bruch;
        ///Finden des Slashzeichen und Rückgabe desen Position
        gefunden = bruch.find("/");
        ///Aufspaltung in zaehler und nenner
        ///Teilstring von "bruch" bilden(zaehler). Von der Stelle 0 bis zur Stelle "gefunden"
        str_zaehler = bruch.substr(0,gefunden);
        ///Teilstring von Bruch bilden(nenner). Von der Stelle gefunden+1 bis zum Ende des Stringes
        str_nenner = bruch.substr(gefunden+1,bruch.length());
    
       ///Umwandlung von String in Int
       ///Umwandlung für den "zaehler"
       string_to_int<<str_zaehler;
       string_to_int>>f.zaehler;
    
       ///Umwandlung von String in Int
       ///Umwandlung für den "nenner"
       string_to_int.clear();
       string_to_int<<str_nenner;
       string_to_int>>f.nenner;
    
        return inside;
    }
    

    includes.h

    #ifndef INCLUDES_H_INCLUDED
    #define INCLUDES_H_INCLUDED
    
    #include <iostream>
    #include <string>
    #include <sstream>
    #include "Fraction.h"
    
    #endif // INCLUDES_H_INCLUDED
    

    main.cpp

    #include "includes.h"
    
    using namespace std;
    
    int main()
    {
    
        Fraction fraction1;
        Fraction fraction2;
    
        cout<<"Geben Sie Ihren 1. Bruch ein!(Inklusive des \" / \")"<<endl;
        cin>>fraction1;
        cout<<"Geben Sie Ihren 2. Bruch ein!(Inklusive des \" / \")"<<endl;
        cin>>fraction2;
    
        cout<<"Addition: "<<fraction1+fraction2<<endl;
        cout<<"Multiplikation: "<<fraction1*fraction2<<endl;
        cout<<"Subtraktion: "<<fraction1-fraction2<<endl;
        cout<<"Division: "<<fraction1/fraction2<<endl;
    
    }
    

    Ich hoffe es macht nicht zu viel Umstände.

    Schönen Samstag noch.

    EDIT:Achja ist mit Code::Blocks geschrieben wurden.



  • Hi!

    Sieht auf den ersten Blick gut aus! Ich hätte aber noch ein paar kleine Verbesserungsvorschläge:
    - Mir fehlen operator== und !=, außerdem +=, -=, *=, /=
    - Die Methoden "kuerzen" und "ggT" würde ich private oder protected machen; gekürzt wird sowieso von alleine und die ggT-Methode gehört eher in eine Mathe-Bib (btw, ggT könnte auch static sein) 🙂
    - Eventuell die Stream-Operatoren auslagern? Brauchen dank get_nenner und get_zaehler auch nicht friend zu sein.

    edit:

    FireFighter schrieb:

    Ich hoffe es macht zu viel Umstände.

    Das hoffe ich auch 😃

    Achso, und wegen der Template-Sache: Wäre evtl nicht schlecht, vor allem da man u.U. doch mal größere Zähler und Nenner braucht als 2 Mrd 🙂 Obwohl das manches vielleicht auch schwieriger macht, denn du bräuchtest dann evtl auch eine Konvertierung von Fraction<int> nach Fraction<unsigned long> oder so..

    Oh, und evtl eine Methode "double asDouble() const" oder so? Falls man den Wert dann doch als Fließkomma-Zahl braucht, wäre das wahrscheinlich nicht schlecht.



  • Hmm, wieso sind denn die Operatoren für den Float-Typen überladen? Wäre int das nicht sinnvoller?



  • warum diese deutsch englich mischung?



  • @Badestrand
    Klasse danke für Deine Meinung, ich werde mich gleich ransetzen und das mit einfügen.
    @stammleser
    --.-- da hast du natürlich recht. Werde ich auch sofort um umändern, danke für dein Beitrag.
    @Tachyon
    Logisch, was ich da wohl gedacht hatte 🙂



  • Bei den ganzen Operatoren muss du ne Referenz zurückgeben



  • Ach die Operatoren sind ja völlig im Arsch



  • klasse danke für dein Edit Badestrand, ich werde es mir zu Herzen nehmen.

    P.S. Ich habe den Fehler geändert 🙂



  • ref schrieb:

    Bei den ganzen Operatoren muss du ne Referenz zurückgeben

    Wie kommst Du denn darauf? Das wäre tötlich.



  • Er hat das mit den Operatoren eh völlig falsch gemacht. Die verändern das Objekt ja gar nicht! Normalerweise gibt man *this zurück als Referenz.



  • soll ja auch so sein, ich will ja nicht das meine Stammobjekte die am anfang eingegeben werden geändert werden sollen 😉



  • rofl



  • ref schrieb:

    Er hat das mit den Operatoren eh völlig falsch gemacht. Die verändern das Objekt ja gar nicht! Normalerweise gibt man *this zurück als Referenz.

    Ist alles gut.

    Fraction a(1,2);
    Fraction b(1,3);
    Fraction c = a + b;
    

    Sollte danach a etwa auch 5/6 sein? Ich denke nicht.



  • hast recht



  • richtig genau das is der Punkt Tachyon. Genau wegen so einem Problem habe ich hier nämlich shconmal im Forum angefragt 🙂


  • Mod

    Die Rückgabe einer Referenz kommt natürlich bei den bereits vorhandenen Operatoren nicht in Frage. Es fehlen auch noch ein paar, einige wurden schon genannt, ich führe nochmal auf
    unär: + -
    binär: == != < > <= >= += -= *= /=
    Eine einfache Konvertierung aus int wäre wünschenswert, es ist relativ natürlich zu schreiben:

    Fraction x = 1;
    

    Sinnvoll würde man hier wohl mit Defaultargumenten arbeiten - insofern halte ich den jetzigen Defaultkonstruktor nicht für günstig, weil er keine Initialisierung durchführt (das kann nat. auch Absicht sein). Für günstiger halte ich

    Fraction(int zaehler=0,int nenner=1);
    

    aber man kann das diskutieren.
    ggT hat nichts mit einer konkreten Instanz von Fraction zu tun, und sollte folglich wenigstens static sein - tatsächlich hat es nicht mal entfernt etwas mit Fraction zu tun - eine freie Funktion ist hier weitaus sinnvoller. Das Problem mit der Interaktion mit float wurde schon angesprochen - das kann man machen, aber da float nicht exakt ist, kann das Ergebnis auch nicht exakt sein, und sollte folglich float sein (analog double, long double). Schließlich erlauben diese Operatoren float-Argumente nur für den rechten Operanden, das ist unintuitiv - die Benutzung von freien Operatoren ist hier absolut angebracht.

    Ob die Streamoperatoren dagegen in der Klasse (+friend) definiert werden, oder erst außerhalb (und möglicherweise nicht friend) ist dagegen absolut und völlig egal. Für den Benutzer spielt es keine Rolle, und auch an der Implementation ändert sich nichts und eine 3. interessierte Partei existiert nicht. Der Kommentar darüber ist allerdings falsch! Was sollen die denn sonst sein, wenn nicht überladene Operatoren?!?



  • Ui, den unären Operator '+' kannte ich gar nicht - sollte der einfach "leer" implementiert werden?



  • ok super danke camper, ich werde deine Hinweise beherzigen und es versuchen soweit umzuschreiben. Ist es denn auch ok wenn ich soviele MEthoden nur für die Operatoren machen? Also ist das bei solchen Klassen normal?

    EDIT: Genau was meinst du mit den unären + -



  • Firefighter schrieb:

    EDIT: Genau was meinst du mit den unären + -

    Für positive und negative Zahlen.

    Fraction a(1,2);
    Fraction b = -a;
    


  • ach du scheiße, daran habe ich ja gar nicht gedacht, stimmt sowas müsste ich noch einfügen. Mal eine Frage wie müsste ich denn += Operator für 2 FRaction objekte bauen?


Anmelden zum Antworten