zwei Brüche Addieren!!


  • Mod

    @kellahha sagte in zwei Brüche Addieren!!:

    @SeppJ das war auch mein erster Gedanken: 😱 😱

    Das bezog sich auf deine Formulierungen.


  • Mod

    Tipp zur Aufgabe: Die Aufgabe hat 6 Sätze. Die ersten 5 davon entsprechen jeweils exakt einer Anweisung in C++ (und der letzte ist 3x die fast gleiche Anweisung hintereinander). Mit diesem Hinweis arbeite dich Satz für Satz vor und übersetze jeden einzeln nach C++. Da du dir komplett unsicher zu sein scheinst, frag ruhig nach jedem Schritt hier noch einmal nach. Aber bitte nicht einfach sinnlos rumraten, sondern gib dir Mühe! Und benutz auch deinen Compiler oder sonstige Programmierwerkzeuge, was die zu deinem Code sagen! Du solltest selber überzeugt sein, dass dein Code richtig ist und dies auch begründen können.

    Also:

    ein Programm main() soll erstellt werden

    Das bekommst du gratis von mir gelöst:

    int main()
    {
    }
    

    Nächster Teil:

    2 Objekte: x und y von datentyp Bruch definiere und initialisieren:
    x= 4/5
    y= 3/10

    Was heißt das in C++? Um das zu beantworten musst du natürlich den Code aus der Vorgabe angucken und verstehen!

    PS: Oder liegt deine Schwierigkeit eher im Entziffern des gebrochenen Deutsch in der Aufgabenstellung? Das können wir dir auch übersetzen.


  • Gesperrt

    @kellahha Hier ist einmal der Anfang, aber um // todo müsstest du dich kümmern:

    #include <iostream>
    
    using namespace std;
    
    class Bruch
    {
    private:
      int zaehler;
      int nenner;
    
    public:
      Bruch(int zaehler, int nenner)
      {
        this->zaehler = zaehler;
        this->nenner = nenner;
      }
      Bruch add(Bruch op)
      {
        // todo
        return *this;
      }
      static Bruch add_2(Bruch op1, Bruch op2)
      {
        // todo
        return op1;
      }
      Bruch operator+(Bruch op)
      {
        // todo
        return *this;
      }
      void print() { cout << zaehler << '/' << nenner << endl; }
    };
    
    void printAll(Bruch *bruchs[], size_t len)
    {
      for (size_t i = 0; i < len; i++)
      {
        bruchs[i]->print();
      }
    }
    
    int main(int argc, char const *argv[])
    {
      /* code */
      Bruch bruch1(5, 15);
      Bruch bruch2(3, 30);
      Bruch *bruchs[3] = {&bruch1, &bruch2};
      printAll(bruchs, 2);
      bruch1 = bruch1.add(bruch2);
      printAll(bruchs, 2);
      Bruch bruch3 = Bruch::add_2(bruch1, bruch2);
      bruchs[2] = &bruch3;
      printAll(bruchs, 3);
      return 0;
    }
    

    printAll hab ich hinzugefügt und sieht leider etwas katastrophal aus...



  • Ich glaube nicht, dass vom TE noch was kommt. Der frecher Versuch, sich die Hausaufgaben machen zu lassen, ist gescheitert, und jetzt sucht er halt woanders nen Dummen.

    @EinNutzer0
    Ich will dir ja nicht zu nahe treten, aber das geht in C++ anders.


  • Gesperrt

    @DocShoe sagte in zwei Brüche Addieren!!:

    Ich will dir ja nicht zu nahe treten, aber das geht in C++ anders.

    Eh, wie denn?



  • @EinNutzer0 sagte in zwei Brüche Addieren!!:

    @DocShoe sagte in zwei Brüche Addieren!!:

    Ich will dir ja nicht zu nahe treten, aber das geht in C++ anders.

    Eh, wie denn?

    Z.B.

    Bruch (int z, int n) : zaehler(z), nenner (n) {};
    

    Den Rest dann gerne, wenn nicht mehr die Gefahr besteht, dass es dennoch genutzt wird.

    Und es wird der operator+ gefordert und nicht operator+=, d.h. return *this ist da schon falsch.


  • Mod

    @EinNutzer0 sagte in zwei Brüche Addieren!!:

    @DocShoe sagte in zwei Brüche Addieren!!:

    Ich will dir ja nicht zu nahe treten, aber das geht in C++ anders.

    Eh, wie denn?

    Du sagst doch selbst, dass dein printAll katastrophal ist. Gänzlich diese Funktion (und allen zugehörigen Hilfscode wie Zeile 48) wegzulassen würde schon sehr helfen.


  • Gesperrt

    @john-0 sagte in zwei Brüche Addieren!!:

    Und es wird der operator+ gefordert und nicht operator+=, d.h. return *this ist da schon falsch.

    Das steht dort nur, weil ich die Implementierung offen lassen wollte...

    Zu printAll ist mir aber nix besseres eingefallen.



  • Generell ist zur Aufgabe noch anzumerken, dass add und operator+ natürlich const sein sollten - und statt print wäre es sinnvoller, den operator<< zu implementieren.



  • Also ich sehe den Anwendungsfall für printAll() nicht. Entweder liegen die einzelnen Brüche als konkrete Variablen vor, dann kann man sie auch separat ausgeben, oder sie liegen in einem Container vor (std::vector, std::array, oder von mir aus auch Bruch[]), dann kann man per std::begin und std::end drüber iterieren und ausgeben.
    Und wenn man eine bequeme Komfortfunktion haben möchte kann man das über variadic templates machen, aber das ist nur Spielerei:

    #include <iostream>
    #include <utility>
    
    struct Bruch
    {
       int N = 1;
       int Z = 1;
    
       Bruch() = default;
       Bruch( int n, int z ) : N( n ), Z( z ) {}
    };
    
    void print( Bruch const& b )
    {
       std::cout << b.N << '/' << b.Z << '\n';
    }
    
    template<typename ...T>
    void print( Bruch const& b, T&&... params )
    {
       print( b );
       print( std::forward<T>( params )... );
    }
    
    int main()
    {
       Bruch b1 { 10, 1 };
       Bruch b2 { 20, 1 };
       print( b1, b2 );
    }
    


  • @wob sagte in zwei Brüche Addieren!!:

    dass add ... natürlich const sein sollten

    Wobei man sich noch überlegen sollte, wo das const hin soll (an den Anfang oder ans Ende ).
    Ich würde jetzt raten, dass eine Memberfunktion "add" das Objekt ändert.
    Wie auch immer, in der Form "Bruch Bruch::add(Bruch op)" jedenfalls eine Katastrophe.


  • Gesperrt

    @DocShoe sagte in zwei Brüche Addieren!!:

    über variadic templates

    Das sieht besser aus, Danke.



  • @Jockelx sagte in zwei Brüche Addieren!!:

    Ich würde jetzt raten, dass eine Memberfunktion "add" das Objekt ändert.

    Hm, ich hatte gedacht, dass die das nicht tun soll, weil sie Bruch returnt, dachte also an operator+ in "unfancy".



  • @wob Klar, kann auch sein. Wie gesagt, bei der Signatur kann man ja nur raten.
    Letztendlich ja auch egal, wichtig ist ja erstmal, dass der TE jetzt weiß, dass die Signatur so wie sie ist, Mist ist.



  • Leute vielen Dank für die Antworten, @DocShoe es sind Keine Hausaufgaben sondern eine Aufgabe von einer alte Klausur, und glaube nicht das das ganze für 2 Punkten ist🤔 . und da ich keine Lösung dafür habe , wollte hier mal fragen, implementieren muss man hier keine Methode...
    @Jockelx Danke trotzdem , musst du aber nicht so werden, da du auf die Fragen hier im Forum nicht antworten musst, lass es, wenn der TE nicht so schreibt wie du gut findest😉



  • @wob sagte in zwei Brüche Addieren!!:

    und statt print wäre es sinnvoller, den operator<< zu implementieren.

    ich persönlich bevorzuge ein toString(). Da kann man dann nutzen wie man lustig ist und der Overhead ist meistens egal.



  • @Tyrdal sagte in zwei Brüche Addieren!!:

    ich persönlich bevorzuge ein toString(). Da kann man dann nutzen wie man lustig ist und der Overhead ist meistens egal.

    Dann heißt es bei der einen Klasse toString(), bei der nächsten to_string() und bei der dritten to_chars() und bei der vierten noch wieder anders. Wenn du generisch beliebige Objekte ausgeben willst, ist das doof. Aber du kannst einfach schreiben:

    std::ostream &operator<<(ostream &os, const DeinT o) { os << o.toString(); return os; }

    Ich würde den Operator immer klein halten - du kannst auch eine Fkt void print_to_stream(ostream&) in deiner Klasse implementieren und die im operator<< aufrufen - damit gehen auch virtuelle Funktionen für <<.



  • Ich hatte ja letzte Woche schon eine Musterlösung mit den exakt gleichen Methodendeklarationen geschrieben. Ich würde das so nicht schreiben, aber egal war nicht die Aufgabenstellung. Man kann die drei Methoden effektiv auf eine zurückführen, so dass der Code nur einmal wirklich vorhanden ist. Ich weiß jetzt nicht, ob das im Sinne des Aufgabensteller war, aber es bietet sich bei der so formulierten Aufgabe halt einfach an.

    #include <cmath>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <stdexcept>
    
    class Bruch {
    	int zaehler;
    	int nenner;
    public:
    	Bruch (const int z, const int n) : zaehler(z), nenner (n) {
    		if (0 == nenner) {
    			throw std::logic_error ("division by zero not defined");
    		}
    	};
    
    	Bruch add (Bruch op) {
    		return Bruch::add_2(*this, op);
    	};
    	static Bruch add_2 (Bruch op1, Bruch op2) {
    		int n = op1.nenner * op2.nenner;
    		int z = (op1.zaehler * op2.nenner) + (op2.zaehler * op1.nenner);
    		int m = sqrt (abs(std::min (n, z))) + 1;
    
    		for (int i = 2; i < m; ++i) {
    			while ((0 == z % i) && (0 == n % i)) {
    				z /= i;
    				n /= i;
    			}
    		}
    
    		Bruch r (z, n);
    		return r;
    	}
    	Bruch operator+ (Bruch op) {
    		return Bruch::add_2(*this, op);
    	};
    
    	void print() {
    		std::cout << zaehler << '/' << nenner << std::endl;
    	}
    };
    
    int main () {
    	try {
    		Bruch a (4, 5);
    		Bruch b (3, 10);
    		//Bruch x (1, 0);
    		a.print();
    		b.print();
    
    		Bruch c = a.add(b);
    		c.print();
    
    		Bruch d = Bruch::add_2 (a, b);
    		d.print();
    
    		Bruch e = a+b;
    		e.print();
    	}
    	catch (std::exception& e) {
    		std::cerr << "exception!!!" << "\n" << e.what() << std::endl;
    
    		return EXIT_FAILURE;
    	}
    
    	return EXIT_SUCCESS;
    }
    

    Nachtrag: Für die Wurzel aus dem Zähler den Betrag ergänzt.


  • Mod

    @john-0 sagte in zwei Brüche Addieren!!:

    Ich hatte ja letzte Woche schon eine Musterlösung mit den exakt gleichen Methodendeklarationen geschrieben. Ich würde das so nicht schreiben, aber egal war nicht die Aufgabenstellung. Man kann die drei Methoden effektiv auf eine zurückführen, so dass der Code nur einmal wirklich vorhanden ist. Ich weiß jetzt nicht, ob das im Sinne des Aufgabensteller war, aber es bietet sich bei der so formulierten Aufgabe halt einfach an.

    Der Sinn der Aufgabenstellung war überhaupt gar nicht, eine Implementierung der Funktionen vorzulegen. Es ging darum, Funktionssignaturen in einen passenden Aufruf zu überführen. Eine durchaus wichtige Grundfähigkeit bei der Nutzung von fremden Libraries. Also die Zeilen 46-59.

    Das sind dann auch (plus Leerzeilen und der Ausgabe von a, b) exakt die 5+3 Zeilen, zu denen ich weiter oben einen Tipp gegeben habe.



  • @wob sagte in zwei Brüche Addieren!!:

    @Tyrdal sagte in zwei Brüche Addieren!!:

    ich persönlich bevorzuge ein toString(). Da kann man dann nutzen wie man lustig ist und der Overhead ist meistens egal.

    Dann heißt es bei der einen Klasse toString(), bei der nächsten to_string() und bei der dritten to_chars() und bei der vierten noch wieder anders. Wenn du generisch beliebige Objekte ausgeben willst, ist das doof. Aber du kannst einfach schreiben:

    std::ostream &operator<<(ostream &os, const DeinT o) { os << o.toString(); return os; }

    Ich würde den Operator immer klein halten - du kannst auch eine Fkt void print_to_stream(ostream&) in deiner Klasse implementieren und die im operator<< aufrufen - damit gehen auch virtuelle Funktionen für <<.

    Tja nu, ich mag die streams in c++ halt so ganz und gar nicht. So hat jeder seine Vorlieben und Abneigungen.


Anmelden zum Antworten