komplexe Zahlen



  • Hallo,

    ich muss ein Programm für komplexe Zahlen schreiben, wobei die Grundrechenarten angewendet und getestet werden sollen. Im Grunde ist es soweit fertig:

    #ifndef KOMPLEXEZAHL_HPP
    #define KOMPLEXEZAHL_HPP
    using namespace std;
    
    class Komplexezahl {
    
        private:     
          double r;  // Realteil 
          double i;  // Imaginaerteil 
    
        public:     
          Komplexezahl(); 
          Komplexezahl(double,double); 
          //Elementfunktionen 
          void ausgabe(); 
          //Operatorfunktionen 
          Komplexezahl operator + (Komplexezahl); 
          Komplexezahl operator * (Komplexezahl); 
          Komplexezahl operator - (Komplexezahl);
          Komplexezahl operator / (Komplexezahl);
    
    };
    
    #endif // KOMPLEXEZAHL_HPP
    
    // komplexezahl.cpp
    
    #include <iostream>
    #include "komplexezahl.hpp"
    
    Komplexezahl::Komplexezahl() {
        r=0;
        i=0;
    };
    
    Komplexezahl::Komplexezahl(double a, double b) {
        r=a;
        i=b;
    };
    
    void Komplexezahl::ausgabe() {
        cout << r;
        if (i>0) cout << "+";
        cout << i << "j";
    };
    
    Komplexezahl Komplexezahl::operator + (Komplexezahl z)
    {   Komplexezahl erg(r+z.r, i+z.i);
        return erg;
    };
    
    Komplexezahl Komplexezahl::operator * (Komplexezahl z)
    {   Komplexezahl erg(r*z.r-i*z.i, r*z.i+i*z.r);
        return erg;
    };
    
    Komplexezahl Komplexezahl::operator - (Komplexezahl z)
    {   Komplexezahl erg(r-z.r, i-z.i);
        return erg;
    };
    
    Komplexezahl Komplexezahl::operator / (Komplexezahl z)
    {   Komplexezahl erg((r*z.r+i*z.i)/(z.r*z.r+z.i*z.i) , (i*z.r-r*z.i)/(z.r*z.r+z.i*z.i));
        return erg;
    };
    
    #include <cstdlib>
    #include <iostream>
    #include "komplexezahl.hpp"
    
    using namespace std;
    
    int main (void) {
    
        Komplexezahl z1(0.0, 1.0), z2(2.0, -3.0);
    
        z1.ausgabe();
        cout << "Fuer die komplexen Zahlen";
        cout << "\n\tz1:   " << z1;
        cout << "\n\tz2:   " << z2;
    
        cout << "\nerhalten wir:";
        cout << "\n\tz1+z2: "<< z1+z2;
        cout << "\n\tz1*z2: "<< z1*z2;
        cout << "\n\tz1-z2: "<< z1-z2;
        cout << "\n\tz1/z2: "<< z1/z2;
    
        cout << endl << endl;
    
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Beim Kompilieren gibt es keine Fehlermeldung, nur unverständliche Warnungen. Allerdings läuft es auch nicht, d.h. es öffnet sich keine Konsole. Es scheint auch keine exe-Datei gebildet zu werden, jedenfalls finde ich keine in dem Ordner, wo es gespeichert ist.

    Ist da noch irgend ein Anfängerfehler drin?

    Danke schonmal für die Hilfe 😋



  • Francisca93 schrieb:

    nur unverständliche Warnungen.

    Dann kann ja nur der Compiler Schuld sein - Nicht.
    Die Warnungen sind für dich unvertändlich.

    Es gibt Leote, die können damit etwas anfangen. Allerdings ist bei den meisten davon die Kristallkugel defekt.

    Darum zeig sie. Per Copy&Paste.



  • Hier nur mal der Anfang (das sind hunderte Zeilen):

    In function 'int main()'::
    ")) << z1'
    candidates are:
    std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]

    no known conversion for argument 1 from 'Komplexezahl' to 'std::basic_ostream<char>::__ostream_type& ()(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& ()(std::basic_ostream<char>&)}'

    std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>, std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]

    no known conversion for argument 1 from 'Komplexezahl' to 'std::basic_ostream<char>::__ios_type& ()(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& ()(std::basic_ios<char>&)}'



  • Das bedeutet, dass cout nicht weiß, was es mit deinem Datentyp anfangen soll. Du musst also entweder eine entsprechende Überladung für den operator<< erstellen oder deine Methode "Komplexezahl::ausgabe" aufrufen.



  • Das sind aber Fehler, keine Warnungen - also kann der Compiler auch keine EXE-Datei erstellen.

    Es gibt keinen Stream-Operator <<(ostream&, ...) für deine komplexe Zahl.
    Du hast aber doch extra eine Funktion ausgabe() dafür erzeugt, also wende sie an:

    z1.ausgabe();
    // sowie
    (z1+z2).ausgabe();
    // etc.
    

    PS: Entferne "using namespace std;" aus der Header-Datei und gewöhne es dir gar nicht erst an.



  • Francisca93 schrieb:

    Hier nur mal der Anfang (das sind hunderte Zeilen):

    Trotzdem muss man sich die anschauen.

    Zumindest die ersten. Der Rest sind auch Folgefehler oder die Gleichen Fehler.

    Francisca93 schrieb:

    no known conversion for argument 1 from 'Komplexezahl' to 'std::basic_ostream<char>::__ostream_type&

    Das solltest du verstehen. Der Compiler kennt etwas nicht.



  • DirkB schrieb:

    Francisca93 schrieb:

    no known conversion for argument 1 from 'Komplexezahl' to 'std::basic_ostream<char>::__ostream_type&

    Das solltest du versthen. Der Compiler kennt etwas nicht.

    Ich kann durchaus nachvollziehen, dass man da als Anfänger erstmal nur Bahnhof versteht.



  • daddy_felix schrieb:

    DirkB schrieb:

    Francisca93 schrieb:

    no known conversion for argument 1 from 'Komplexezahl' to 'std::basic_ostream<char>::__ostream_type&

    Das solltest du versthen. Der Compiler kennt etwas nicht.

    Ich kann durchaus nachvollziehen, dass man da als Anfänger erstmal nur Bahnhof versteht.

    Darum ja der Hinweis, wo man schauen muss.
    Es nützt ja der TO auf Dauer nichts, wenn wir die magische Antwort (auch ohne Fehlermeldung) kennen.



  • Ich konnte dem Übungsgruppenleiter per Mail noch die Hinweise entlocken, dass in die hpp-Datei noch die Zeile

    friend ostream &operator<< ( ostream &, const Komplexezahl &);

    eingefügt werden muss, und in cpp

    ostream &operator<< ( ostream &ostr, const Komplexezahl &a)
    {
        ostr << a.r;
        if(a.i>=0) ostr << "+";
        ostr << a.i << "j";
        return ostr;
    };
    

    Ich versteh zwar nur Bahnhof, aber immerhin läuft es jetzt.

    Nun soll das Programm aber noch erweitert werden um den Zuweisungsoperatot "=". Dafür hab ich in cpp hinzugefügt:

    Komplexezahl Komplexezahl::operator = (Komplexezahl z)
    {   Komplexezahl erg(r=z.r, i=z.i);
        return erg;
    };
    

    und die entsprechende Deklaration in hpp. (Müsste doch so stimmen?). Jetzt soll die Funktion aber auch in der main-Methode getestet werden - da fehlt mir gerade so ein bisschen die Idee wie das gehen könnte...



  • Francisca93 schrieb:

    Ich versteh zwar nur Bahnhof, aber immerhin läuft es jetzt.

    Das ist schlecht, denn dann hilft es dir ja nicht weiter. Warum überhaupt "friend"? Suche mal nach: "Prefer writing nonmember nonfriend functions"!

    Nun soll das Programm aber noch erweitert werden um den Zuweisungsoperatot "=". Dafür hab ich in cpp hinzugefügt:

    Komplexezahl Komplexezahl::operator = (Komplexezahl z)
    {   Komplexezahl erg(r=z.r, i=z.i);
        return erg;
    };
    

    und die entsprechende Deklaration in hpp. (Müsste doch so stimmen?).

    Nein, das ist so nicht richtig. Der operator= soll doch das Objekt, auf das er angewendet wird, ändern und auch zurückgeben. Erkläre mal, was hier passiert bzw. passieren soll bzw. warum du diese Zeile so geschrieben hast: Komplexezahl erg(r=z.r, i=z.i);

    Lies dir durch und versuche zu verstehen:
    a) http://en.cppreference.com/w/cpp/language/operators und http://en.cppreference.com/w/cpp/language/operator_assignment
    b) https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading

    Dazu gibt es bestimmt noch viel mehr Erklärungen.



  • Erkläre mal, was hier passiert bzw. passieren soll bzw. warum du diese Zeile so geschrieben hast: Komplexezahl erg(r=z.r, i=z.i);

    Naja, z1=z2 soll ja die Abkürzung sein für z1.operator=(z2)

    Auf z1 wird der Operator angewendet, und z2 wird als Argument übergeben (so wie bei + und - auch). So müsste ja dann der Realteil der als Argument übergebenen Zahl den Realteil der ersten überschreiben, und beim Imaginärteil genauso?



  • Richtig, der ersten. Du aber erstellst eine neue Zahl und änderst die erste Zahl nicht.



  • Doch sicher wird die erste Zahl geändert. Wegen der beiden Zuweisungen innerhalb der Parameter des Konstruktoraufrufs der Kopie. Oder irre ich? Ist auch egal: das würde ich so niemals schreiben, das verwirrt doch nur!



  • Francisca93 schrieb:

    Erkläre mal, was hier passiert bzw. passieren soll bzw. warum du diese Zeile so geschrieben hast: Komplexezahl erg(r=z.r, i=z.i);

    Naja, z1=z2 soll ja die Abkürzung sein für z1.operator=(z2)

    Auf z1 wird der Operator angewendet, und z2 wird als Argument übergeben (so wie bei + und - auch). So müsste ja dann der Realteil der als Argument übergebenen Zahl den Realteil der ersten überschreiben, und beim Imaginärteil genauso?

    Wie gut, dass du an meiner Frage vorbei antwortest... z1 und z2 kommen beide in der Zeile nicht vor.



  • z1 und z2 waren nur Beispiele für beliebige komplexe Zahlen. Du kannst es von mir aus auch a und b nennen.

    Zum "testen" hab ich jetzt in die main-Methode unten noch diese Zeilen eingefügt:

    z1=z2;
        cout << "\n\n\tz1 neu: "<< z1;*/
    

    Das scheint zu funktionieren. Es wird dann Real- und Imaginärteil von z2 angezeigt, obwohl z1 ausgegeben wurde. Das ist doch gerade das, was der Zuweisungsoperator machen soll?



  • Francisca93 schrieb:

    Erkläre mal, was hier passiert bzw. passieren soll bzw. warum du diese Zeile so geschrieben hast: Komplexezahl erg(r=z.r, i=z.i);

    Naja, z1=z2 soll ja die Abkürzung sein für z1.operator=(z2)

    Auf z1 wird der Operator angewendet, und z2 wird als Argument übergeben (so wie bei + und - auch). So müsste ja dann der Realteil der als Argument übergebenen Zahl den Realteil der ersten überschreiben, und beim Imaginärteil genauso?

    Genau, z1 = z2 soll eine Abkürzung sein für z1.operator=(z2), aber es gibt Unterschiede zwischen dem + Operator und dem = Operator.

    Der + Operator bekommt, je nach Implementierung, zwei Parameter, (oder als Member Implementierung einen) und erstellt ein neues Objekt der Klasse. Die Summanden sollen ja schließlich ihre Werte nicht ändern.

    Der = Operator ändert ein bereits bestehendes Objekt so, dass es den selben Zustand, wie das Übergebene Objekt hat.

    An welcher Stelle überschreibst du den Real und Imaginärteil in deinem Operator aufruf? Tipp: wob hat das schon verraten.

    Edit:

    Francisca93 schrieb:

    Das scheint zu funktionieren. Es wird dann Real- und Imaginärteil von z2 angezeigt, obwohl z1 ausgegeben wurde. Das ist doch gerade das, was der Zuweisungsoperator machen soll?

    Das ist, was der Operator machen soll, allerdings ist der Großteil deines Codes dafür völlig unerheblich und sorgt eher für Verwirrung.



  • wob schrieb:

    Francisca93 schrieb:

    Erkläre mal, was hier passiert bzw. passieren soll bzw. warum du diese Zeile so geschrieben hast: Komplexezahl erg(r=z.r, i=z.i);

    Naja, z1=z2 soll ja die Abkürzung sein für z1.operator=(z2)

    Auf z1 wird der Operator angewendet, und z2 wird als Argument übergeben (so wie bei + und - auch). So müsste ja dann der Realteil der als Argument übergebenen Zahl den Realteil der ersten überschreiben, und beim Imaginärteil genauso?

    Wie gut, dass du an meiner Frage vorbei antwortest... z1 und z2 kommen beide in der Zeile nicht vor.

    müssen sie auch nicht. Der Operator ist eine Memberfunktion und r sowie i sind Member. Daher steht da implizit

    Komplexezahl erg(this->r=z.r, this->i=z.i);

    Und "z" ist der übergebene Parameter, steht also in dem Beispiel für "z2".

    Aber ja, man muss schon sehr genau hinschauen, um das zu erkennen.


  • Mod

    daddy_felix schrieb:

    Aber ja, man muss schon sehr genau hinschauen, um das zu erkennen.

    Vor allem habe ich stark den Verdacht, dass da nur der Zufall am Werk war. Sieht doch sehr danach aus, als hätte da jemand named parameters (a la Python und anderen Sprachen) benutzen wollen und es kam unbeabsichtigt die korrekte Zuweisung heraus.

    Leider ist Francisca93 nicht auf die Frage eingegangen, was der Plan hinter dieser Zeile war.



  • daddy_felix schrieb:

    wob schrieb:

    Wie gut, dass du an meiner Frage vorbei antwortest... z1 und z2 kommen beide in der Zeile nicht vor.

    müssen sie auch nicht.

    Das sehe ich anders. Wenn ich nach A frage und du irgendwas zu B erklärst, passt das auch nicht.

    Ich hatte mit meiner Frage bezwecken wollen, dass genau diese Zeile erklärt wird und dabei hoffentlich klar wird, warum was wie passiert. Die Antwort von Francesca geht aber gar nicht auf diese Zeile ein, sondern beschreibt nur generelles Blabla, was die gesamte Funktion tun soll. Eine Antwort, die diese Zeile beschreibt, enthält Erklärungen, was erg ist, was r=z.r bedeutet usw. Sie könnte also anfangen mit "Es wird ein neues Objekt vom Typ Komplexezahl namens erg erzeugt. Dazu wird der Konstruktor, der 2 doubles als Parameter hat, aufgerufen. Als Parameter werden übergeben: ..." Damit sollte klar werden, warum das so zumindest ansatzweise funktioniert (ich habe nämlich dieselbe Befürchtung wie SeppJ bzgl. Named Parameter)

    Die ... sind dann der interessante Teil der Beschreibung.



  • SeppJ schrieb:

    Leider ist Francisca93 nicht auf die Frage eingegangen, was der Plan hinter dieser Zeile war.

    Einen Plan gab es nicht, es war nur so eine Eingebung 😉


Log in to reply