Benutzerdefinierter Dateityp: Operatoren definieren



  • Unsere Aufgabe in dieser Woche ist es, Felder eines beliebigen Datentyps ElemT
    einzulesen und zu sortieren.
    Die Sortieralgorithmen habe ich bereits in der letzten Woche programmiert, und
    muss sie somit nur noch anpassen.

    Insgesamt müssen 3 Felder sortiert werden:
    double-Feld doubles.txt
    string-Feld strings.txt
    Student-Feld student.txt

    Für den benutzerdef. Datentyp 'Student' steht bereits ein Grundgerüst bereit,
    das um einen Ausgabeoperator '<<', sowie Vergleichsoperatoren '<', '==' und '!='
    ergänzt werden soll.
    Und hier enstehen für mich als absoluten Anfänger direkt Schwierigkeiten:

    Hier einmal das Grundgerüst:

    #include "student.h"
    
    // Eingabeoperator ">>"
    std::istream& operator>> ( std::istream& s, Student& a)
    {
        s >> a.Vorname >> a.Nachname >> a.MatNr >> a.Note;
        return s;
    }
    
    // Ausgabeoperator "<<"
    std::ostream& operator<< ( std::ostream& s, const Student& a)
    {
        // hier den Ausgabeoperator definieren
    }
    
    // Vergleichsoperator "<"
    bool operator< ( const Student&, const Student&)
    {
        // hier fehlt was
    }
    
    // Vergleichsoperatoren "==" bzw. "!="
    bool operator== ( const Student&, const Student&)
    {
        // hier fehlt was
    }
    
    bool operator!= ( const Student&, const Student&)
    {
        // hier fehlt was
    }
    

    Meine Ideen:
    - Ausgabeoperator: Ich weiß leider nicht wie ich die 4 Merkmale (Vorn., Nachn., Matr.nr. und Note wie gewünscht ausgeben kann)

    - Vergleichsoperator <:
    Hier vergleiche ich Zeichen für Zeichen:
    Ist a[i] < b[i] so ist a<b.
    - Vergleichsoperator ==:
    Zuerst Länge vergleichen: untersch. Längen => false
    Ansonsten Zeichen für Zeichen: if a[i] != b[i], dann false
    - Vergleichsoperator !=:
    Umkehrfkt. zu ==, also dessen Ergebnis negieren.

    Im Code würde das bei mir nun so ausschauen:

    #include "student.h"
    
    // Eingabeoperator ">>"
    std::istream& operator>> ( std::istream& s, Student& a)
    {
        s >> a.Vorname >> a.Nachname >> a.MatNr >> a.Note;
        return s;
    }
    
    // Ausgabeoperator "<<"
    std::ostream& operator<< ( std::ostream& s, const Student& a)
    {
        // hier den Ausgabeoperator definieren
    }
    
    // Vergleichsoperator "<"
    bool operator< ( const Student& a, const Student& b)
    {
    std::size_t min_length = std::min(a.length(), b.length());
    
        for(std::size_t i = 0; i < min_length; ++i){
            if(a[i] < b[i]){
                return true;
            }
            if(a[i] > b[i]){
                return false;
            }
        }
    
        if(a.length() >= b.length()){
            return false;
        }
    
        return true;
    }
    
    // Vergleichsoperatoren "==" bzw. "!="
    bool operator== ( const Student& a, const Student& b)
    {
    if(a.length() != b.length()){
            return false;
        }
    
        for(std::size_t i = 0; i < a.length(); ++i){
            if(a[i] != b[i]){
                return false;
            }
        }
    
        return true;
    }
    
    bool operator!= ( const Student& a, const Student& b)
    {
    return !(a == b);
    }
    

    Wäre für jeden Tipp, sowie Hilfe (vor allem bei dem Ausgabeoperator) dankbar 🙂

    VG



  • Du weißt wie die Daten eingelesen werden sollen. Damit weißt du ja auch, wie sie geschrieben werden könnten.
    Du brauchst nur ein Trennzeichen zwischen den Werten.
    (Wie stehen sie denn in student.txt? 😉 )

    Wie sollen denn die Studenten sortiert werden?
    (Was macht das length oder []-Operator?)

    Sollten bei Vergleichen nicht alle Eigenschaften verglichen werden?

    Btw, du musst nur operator< implementieren... == und != lassen sich damit ausdrücken.

    std::string::compare könnte das vereinfachen...



  • Ein Beispiel:
    Carl-Friedrich Gauss 111111 1.0

    student.txt besteht aus 12 solcher Einträge.

    Die Einträge sollen aufsteigend nach Nachnamen, bei gleichen Nachn. nach Vornamen, sortiert werden.

    Jetzt fällt mir auf, dass ich die Operatoren da wohl noch anpassen muss 😃
    (bzgl. der versch. Eigenschaften)

    Ich versuche das mal für '<':

    bool operator< ( const Student& a, const Student& b)
    {
    std::size_t min_nachname = std::min(a.Nachname.length(), b.Nachname.length());
    std::size_t min_vorname = std::min(a.Vorname.length(), b.Vorname.length());
        //gleiche Nachnamen
        if(a.Nachname == b.Nachname){ 
           for(std::size_t i = 0; i < min_vorname; ++i){
               if(a.Vorname[i] < b.Vorname[i]){
                  return true;
               }
               if(a.Vorname[i] > b.Vorname[i]){
                  return false;
               }
           }
           if(a.Vorname.length() >= b.Vorname.length()){
             return false;
           }
    
           return true;
    
        }
        for(std::size_t i = 0; i < min_nachname; ++i){
            if(a.Nachname[i] < b.Nachname[i]){
                return true;
            }
            if(a.Nachname[i] > b.Nachname[i]){
                return false;
            }
        }
    
        if(a.Nachname.length() >= b.Nachname.length()){
            return false;
        }
    
        return true;
    }
    

    Hier stellt sich mir noch eine Frage:
    In der Abfrage

    if(a.Nachname == b.Nachname)
    

    greife ich ja auf den '=='-Operator zurück.
    Nun weiß ich nicht wie ich '==' mit '<' ausdrücken kann 😕

    EDIT: Werde mir das mit dem std::string::compare mal ansehen. Das scheint einfacher zu sein


  • Mod

    Um deine direkte Frage zu beantworten: Wenn etwas weder < noch > ist, dann ist es ==. Und > kannst du als < schreiben, indem du einfach beide Seiten umdrehst.

    Aber: Der Vergleich der einzelnen Namensbestandteile ist nicht Aufgabe des Studenten-Vergleichsoperators. Haben die Datentypen für Vor- und Nachname denn keine eigenen Vergleichsoperatoren? Falls sie welche haben: Nutze diese! Falls sie keine haben: Schreib welche und nutze diese!

    Somit wird dann der Studenten-Vergleichsoperator sowohl einfacher als auch robuster gegen Änderungen und Fehler.



  • Habe jetzt noch im Netz nachgeschaut (bin wirklich ein absoluter Neuling in Sachen C++):

    In C++ kann ich Zeichenketten vom Typ string einfach mit Hilfe von
    ==, !=, <, >, <=, => miteinander vergleichen oder?

    Nun nehme ich mal 2 Dateien vom Typ student:

    Pierre-Louis Lions 301979 1.3
    Jacques-Louis Lions 271954 1.3

    Angenommen es sei
    a= Pierre-Louis Lions 301979 1.3,
    b= Jacques-Louis Lions 271954 1.3
    Weiß C++, dass a.Nachname vom Typ string ist?

    Dann würde mein '<' für Student ja wie folgt ausschauen:

    // Vergleichsoperator "<"
    bool operator< ( const Student& a, const Student& b)
    {
        if (a.Nachname == b.Nachname){ //gl. Nachname
          if(a.Vorname < b.Vorname){
             return true;
            }
          return false;
        } 
        if (a.Nachname < b.Nachname){
           return true;
        }
        return false;
    }
    

    EDIT: Oder kann ich durch

    string a.Nachname, b.Nachname;
    

    die einzelnen Einträge jeweils dem Typ string zuweisen?



  • Student definiert Nachname. Da musst du nichts mehr machen.



  • Die Variable "Nachname" hat doch schon einen Datentyp, schau mal in die Klasse "Student"



  • Stimmt,
    Habe es nun in einer anderen Datei gesehen.

    struct Student
    {
        std::string Vorname, Nachname;
        int         MatNr;
        double      Note;
    };
    

    D.h. dass ich Nachnamen also mit '<' usw. vergleichen kann.

    Edit: Ich füge mal die anderen Operatoren hinzu (bin gerade dabei)

    // Vergleichsoperatoren "==" bzw. "!="
    bool operator== ( const Student& a, const Student& b)
    {
        if(a < b){
           return false;
        }
        if(a > b){ //muss noch implementiert werden
           return false;
        }
        return true;
    }
    
    bool operator!= ( const Student& a, const Student& b)
    {
        return !(a == b); //auf == zurückgreifen, und das Ergebnis negieren 
    }
    
    bool operator> ( const Student& a, const Student& b) //Mein Versuch für '>'
    {
        if (a.Nachname == b.Nachname){ //gl. Nachname
          if(a.Vorname > b.Vorname){
             return true;
            }
          return false;
        }
        if (a.Nachname > b.Nachname){
           return true;
        }
        return false;
    }
    

    Wie schaut es soweit aus? 🙂



  • Wenn nicht a>b und nicht b>a gilt, gilt dann nach deiner Implementierung a==b? Immer?



  • Hab's heute fertig gestellt.
    Danke an alle 🙂


Anmelden zum Antworten