Hilfe bei Referenz Rückgabe mit Operatorüberladung



  • Hallo ich schreibe gerade zu Übungszwecken eine eigene Klasse String.

    String.h

    #ifndef STRING_HPP
    #define STRING_HPP
    
    #include <iostream>
    
    using namespace std;
    
    class String
    {
        private:
            char* buf;
            int len;
    
        public:
            String (char* s="");
            String (char c, int n);
            String (String& src);
            ~String();
            int length();
            char* getStr();
            void setAt(int i, char newchar);
            char getAt(int i);
    
            String operator+(String& src);
            //String operator+=(String &src);
            String& operator=(String &src);
    
            friend ostream& operator<< (ostream &os, String &src);
    };
    
    #endif // TEXT_HPP
    

    String.cpp

    #include "String.h"
    
    String::String(char* s)
    {
        int counter = 0;
        int laenge = 0;
    
        while(s[counter] != '\0')
        {
            laenge++;
            counter++;
        }
    
        buf = new char[laenge];
    
        for(int i=0; i<laenge; i++)
        {
            buf[i] = s[i];
        }
    
        buf[laenge] = '\0';
    
        len = laenge;
    }
    
    String::String(char c, int n)
    {
        buf = new char[n+1];
        for(int i=0;i<n; i++)
        {
            buf[i] = c;
        }
        buf[n] = '\0';
    
        len = n;
    }
    
    String::String(String& src)
    {
        buf = new char[src.length()+1];
        len = src.length();
    
        for(int i=0; i<src.length(); i++)
        {
            buf[i] = src.getAt(i);
        }
        buf[src.length()] = '\0';
    }
    
    String::~String()
    {
        delete[] buf;
    }
    
    int String::length()
    {
        return len;
    }
    
    char* String::getStr()
    {
        return buf;
    }
    
    void String::setAt(int i, char newchar)
    {
        buf[i] = newchar;
    }
    
    char String::getAt(int i)
    {
        return buf[i];
    }
    
    ostream& operator<<(ostream& os, String& src)
    {
        os << src.getStr();
        return os;
    }
    
    String& String::operator=(String &src)
    {
        String neu(src);
        return neu;
    }
    
    String String::operator+(String &src)
    {
        String neu('c', this->length()+src.length());
    
        for(int i=0; i<this->length(); i++)
        {
            neu.setAt(i, this->getAt(i));
        }
        int counter = 0;
        for(int i=this->length(); i<this->length()+src.length(); i++)
        {
            neu.setAt(i, src.getAt(counter));
            counter++;
        }
    
        cout<<neu<<endl;
        return neu;
    }
    

    Speziell geht es um den + Operator. Mein Lehrer meinte es geht nur mit Referenzen wobei ich mich schon Frage wieso das so sein sollte?
    Mein Problem ist Momentan wenn ich keine Referenz verwende kann der Operator sich auf nichts beziehen dann bekomme ich den Error "No match for Operator = " obwohl ich das auch schon komisch finde.

    Und wenn ich eine Referenz verwende weiß ich nicht was ich zurückgeben soll, da so wie ich es gemacht habe nicht klappen kann, da es das Objekt ja nur in der Funktion gibt und es anschließend weg ist.
    Wenn ich ein Objekt mit dem new Operator erstelle funktioniert das ganze bei mir auch noch nicht ganz. Zurück geben tu ich dann einfach die Adresse, da eine Referenz ja auch eine Adresse ist, aber trotzdem funktioniert das dann in der main.cpp nicht und er gibt mir einen leeren String aus. In der Funktion hat der String neu aber einen Wert, so dass ich mir sicher bin das meine Funktion von der Logik her funktioniert.

    Mit freundlichen Grüßen
    Theroth


  • Mod

    Dein Operator= ist nicht so toll implementiert und hat zudem noch eine hinderliche Signatur, da er keine const-Objekte annehmen kann. Googel mal "copy-swap idiom". Achte auch auf const-correctness!

    Ansonsten siehe auch allgemein zu Operatorüberladung:
    https://www.c-plusplus.net/forum/232010



  • Zu deinem Konstruktor:

    Theroth schrieb:

    String::String(char* s)
    {
        int counter = 0;
        int laenge = 0;
    
        while(s[counter] != '\0')
        {
            laenge++;
            counter++;
        }
    
        buf = new char[laenge];
    
        for(int i=0; i<laenge; i++)
        {
            buf[i] = s[i];
        }
    
        buf[laenge] = '\0';
    
        len = laenge;
    }
    

    Erstens: wozu zwei Variable laenge und counter?
    Zweitens: Spiel doch mal einen einfachen Fall durch: jemand ruft den obigen Konstruktor mit dem Leerstring "" als Parameter auf. Wie groß ist counter/laenge dann? Wie viele Bytes werden durch new reserviert? Wohin schreibt buf[laenge] ? Oder anders gefragt: wo ist der Platz für \0 ?

    Ansonsten gelten SeppJs Kommentare.



  • Erstmal danke an beide für die Hilfe.

    Ich verstehe nicht warum mein Operator = keine const Objekte annehmen kann. Const ist doch kein eigener Datentyp, sondern nur eine Spezifizierung von einem Objekt oder nicht? ich habe auch das problem wenn ich const angebe, kann ich die Methoden des Objektes nicht mehr verwenden wo const vorsteht. Ist das so vorgesehen oder mach ich da auch was falsch? Schreibe "const Objekt& Name".

    Warum ich zwei Variablen habe weiß ich auch gerade nicht das stimmt counter ist unnötig. Den Fall durchspielen hab ich gemacht. Meines wissens nach wäre Counter dann 0 also würde \0 auf den ersten Array Platz geschrieben werden da es keine anderen Indizes gibt. Wie viele Bytes reserviert werden und wohin buf schreibt weiß ich nicht genau, bzw. was meinst du mit wohin schreibt buf[laenge]?`

    Ich muss leider auch Zugeben, das ich das copy-swap idiom gegoogelt habe daraus aber nicht so schlau geworden bin. Ich vermute aber das ich den Speicherplatz nicht mehr freigegeben habe, da in den Beispielen immer ein delete drin steht.

    Mit freundlichen Grüßen

    Theroth



  • Probiere einfach mal:

    const String s1("Test"); // Übergabe eines String-Literals (welches auch konstant ist)
    String s2;
    
    s2 = s1; // hier Übergabe eines konstanten Strings
    

    Falls dein Compiler in der ersten Zeile nicht meckert, dann stell die Warnungen höher (verwendest du Microsoft Visual Studio?).

    Und damit du Lesefunktionen auf konstanten Strings aufrufen kannst, mußt du die Funktion selbst als 'const' deklarieren, z.B.:

    int length() const;
    

    Dann geht auch

    const String s;
    
    int len = s.length();
    

    (auch hier noch der Tipp, daß size_t der bessere Rückgabetyp wäre)



  • Okay herzlichen Dank.

    Nein ich verwende momentan Codeblocks. Ich habe die Warnungen mal etwas höher gestellt.



  • Theroth schrieb:

    Den Fall durchspielen hab ich gemacht. Meines wissens nach wäre Counter dann 0 also würde \0 auf den ersten Array Platz geschrieben werden da es keine anderen Indizes gibt. Wie viele Bytes reserviert werden und wohin buf schreibt weiß ich nicht genau, bzw. was meinst du mit wohin schreibt buf[laenge]?

    Wieso weißt du nicht, wieviel Speicher du reservierst? Du machst doch selbst new char[laenge]; . Und da Länge, wie du richtig berechnet hast, 0 ist, hast du dir hier ein Array der Länge 0 reserviert. Mit buf[0] = '\0'; würdest du aber auf das ERSTE Array-Element zugreifen. Das gibt es aber nicht.

    Schau dir mal die new-Aufrufe der anderen Funktionen an. Da findest sich jeweils ein +1, das hier fehlt.


Anmelden zum Antworten