Stringklasse,operatorüberladung...arghl



  • Hallo leute,
    zu übungszwecken wollt ich mal eine übungsklasse string schreiben
    hab da aber 2 probleme...

    erstens, beim operator + passiert fehler, und operator == macht auch nich das was er soll:

    const int MSIZE=1024;
    class MeinString
    {
    public:
     MeinString(){chr=new char[MSIZE];chr="";}
     MeinString(const char* _text){chr=new char[MSIZE];strcpy(chr,_text);}
     void Drucke()const {cout<<chr;}
     static bool isequal(MeinString &s1,MeinString &s)
     {
      if(strcmp(s1.chr,s.chr)==0)
       return true;
      else
       return false;
     }
     MeinString operator+(MeinString &rhs)
     {
      char* chr1 = strcat(chr,rhs.chr);
      return MeinString(chr1);
     }
    private:
     char* chr;
    };
    bool operator==(MeinString &rhs,MeinString &lhs)
    {
     return MeinString::isequal(rhs,lhs);
    }
    

    Main:

    int main(int argc, char* argv[])
    {
    MeinString str("hallo");
    MeinString str2("test");
    MeinString str4("hallo");
    MeinString str3=str+str2;  //wird auch str zu hallotest,nicht nur str3
    str.Drucke();
    cout<<endl;
    str3.Drucke();
    str3=str2;
    cout<<endl;
    str3.Drucke();
    
    cout<<endl;
    if(str==str4)       //hier kommt false heraus,obwohl sie doch gleich sind....
     cout<<"gleich";
    else
     cout<<"false";
    getch();        return 0;
    
    }
    

    da stellt sich mir die frage, wie überlade ich ==, +=, [] und so richtig?!



  • sorry, da ist so ziemlich alles falsch...

    const int MSIZE=1024;
    class MeinString
    {
    public:
     MeinString(){chr=new char[MSIZE];chr="";}
     //erst speicher allokiert und dann den speicher weggeschmissen
     //und warum konstante größe? dann mach doch gleich ein array auf dem stack
    
     MeinString(const char* _text){chr=new char[MSIZE];strcpy(chr,_text);}
     //wass wenn strlen(_text) > MSIZE ?
    
     void Drucke()const {cout<<chr;}
     //lieber operator<< überladen
    
     //const correctness beachten 
     static bool isequal(MeinString &s1,MeinString &s)
     {
      //return !strcmp(s1.chr, s.chr) ist schöner
      if(strcmp(s1.chr,s.chr)==0)
       return true;
      else
       return false;
     }
     //operator+ sollte kein member sein
     //du veränderst this
     //was wenn strlen(chr) + strlen(rhs.chr) > MSIZE
     MeinString operator+(MeinString &rhs)
     {
      char* chr1 = strcat(chr,rhs.chr);
      return MeinString(chr1);
     }
    private:
     //chr ist ein komischer name für einen zeiger
     char* chr;
    };
    //const correctness beachten
    //rhs und lhs vertauscht
    bool operator==(MeinString &rhs,MeinString &lhs)
    {
     return MeinString::isequal(rhs,lhs);
    }
    


  • nee das is ne aufgabe die ich mache:

    Stringklasse, Zeichenkette darf maximal 1024 sein!
    Konstruktor der leere Zeichenkette erzeugt

    Memberfunktion Drucke()
    Operator +, = und ==

    kannst mir mal das mit der operatorüberlaunf richtig zeigen hier =/!

    Fragen:
    array auf dem stack?

    Rechtfertigungn 😉

    eigentlich mach ich bei zeigern ein p davor...
    und rhs und lhs vertauscht, sorry unbeabsichtigt...



  • Hi,

    dynamisch allokierte Arrays auf dem Heap, sind, wie der Name schon sagt, dafür gedacht, dass sie dynamisch funktionieren und daher zum Beispiel ihre Größe durch eine Eingabe des Benutzers erhalten oder durch davon abgeleitete Berechnungen.
    In deinem Fall ist die Größe sowieso konstant, weswegen es nichts bringt hier dynamisch zu allokieren.

    Eisflamme



  • wenn MSIZE in der angabe festgelegt wird dann vergiss meine kommentare bezüglich MSIZE. alle anderen sachen sind immernoch gültig und sollten von dir geändert werden. uU ist Drucke auch so in der angabe drinnen, dann kannst du meinen kommentare diesbezüglich auch vergessen.

    du kannst gerne genau nachfragen.



  • hi,

    @Shade: Wieso sollte operator+ kein Member sein? 😕



  • Man.bloed schrieb:

    Konstruktor der leere Zeichenkette erzeugt

    Dann sollte dein ctor so aussehen

    MeinString()
    {
        //...
        chr[0] = '\0';
    }
    

    Shade Of Mine schrieb:

    //return !strcmp(s1.chr, s.chr) ist schöner
    

    Noch schöner fänd ich

    return strcmp(s1.chr, s.chr) == 0;
    

    😃

    Man.bloed schrieb:

    array auf dem stack?

    Statt im ctor dynamisch Speicher zu reserieren, hast du einfach folgenden Member

    char chr[MSIZE];
    

    Man.bloed schrieb:

    eigentlich mach ich bei zeigern ein p davor...

    Ich glaube nicht, dass das Shade gemeint hat. Aber ein

    char* inhalt;
    

    oä ist irgendwie aussagekräftiger, findest du nicht auch?

    btw:
    Wenn du richtig beeindrucken willst, dann vergiss das mit der C-String Kapselung und mach 'ne vernünftige String Klasse daraus. 🙂 😉



  • bluecode schrieb:

    @Shade: Wieso sollte operator+ kein Member sein? 😕

    konsistenz.

    int+int == int

    da kann der op+ technisch gesehen member sein. aber bei
    int+float == float

    kann er es nicht mehr vernünftig. da ist er global wesentlich besser.

    und ob
    int+int==int
    member oder global ist, ist egal.

    also lieber alles global, dann ist alles schön beisammen.

    der op+ als member hat ja einen lustigen pitfall:

    Foo operator+(Foo const& other)
    {
      Foo temp(other);
      temp+=*this;
      return temp;
    }
    

    finde den fehler



  • Was mich wundert ist, dass Shade noch gar nicht auf ECP11 eingegangen ist. Naja, dann fass ich es mal zusammen.

    Beachte folgenden Fall:

    MeinString a("foo");
    MeinString b = a;	// Copy-Konstruktor wird aufgerufen
    

    Wie du siehst, wird der Copy-Konstruktor aufgerufen. Den hast du aber nicht definiert. Deshalb wird der Standard-Copy-Konstruktor erzeugt und aufgerufen, der jede einzelne Member-Variable kopiert. Weil du einen Zeiger für den String benutzt, wird die Adresse, auf die a.chr zeigt, nach b.chr kopiert, womit a und b auf dieselbe Stelle zeigen. Wenn jetzt der Destruktor von a aufgerufen wird (btw: den hast du noch gar nicht, einfaches delete [] chr;), zeigt b.chr auf eine ungültige Stelle.

    Dasselbe gilt übrigens auch beim Zuweisungsoperator:

    MeinString a("foo");
    MeinString b = "bar";
    b = a;
    

    Hier gibt es aber noch ein weiteres Problem. b.chr hat vorher auf "bar" gezeigt, und der Wert von b.chr wird einfach mit dem Wert von a.chr überschrieben, sodass nie ein delete[] auf "bar" ausgeführt wird.

    Und noch etwas tückisches beim Copy-Konstruktor:

    void MyFunction(MeinString foo) {}
    
    MeinString bar = "Tach auch.";
    MyFunction(bar);
    

    Der Parameter von MyFunction wird by value übergeben, sodass der Copy-Konstruktor für foo mit dem Parameter bar aufgerufen wird. Das selbe Spielchen wie gehabt: bar.chr und foo.chr zeigen auf dieselbe Speicherstelle. Jetzt lebt foo aber ziemlich kurz und es wird beim Verlassen der Funktion schon wieder der Destruktor aufgerufen, der ein delete[] chr; ausführt, womit bar auf ungültigen Speicher zeigt.



  • Sorry hab grad wenig zeit...hab nur shades gelesen...

    Aber genauer nachgefragt: wie muss den den + operator aussehen das er funktioniert?
    Das gleiche beim ==?

    denn

    static bool isequal(MeinString &s1,MeinString &s)
     {
      return !strcmp(s1.chr, s.chr);
     }
    //und
    
    bool operator==(MeinString &rhs,MeinString &lhs)
    {
     return MeinString::isequal(rhs,lhs);
    }
    

    funktionieren nicht!



  • Man.bloed schrieb:

    funktionieren nicht!

    kleiner tipp: nie eine Fehlerbeschreibung geben, wir lieben ein gutes Rätsel



  • hab doch schon ganz am anfang gesagt was nich geht:
    Operator +:

    MeinString str("hallo");
    MeinString str2("test");
    MeinString str4("hallo");
    MeinString str3=str+str2;
    

    da wird nicht nur aus str3 hallotest, sondern auch aus str (aber str soll sich ja nich verändern)

    Und equal:
    da liefert immer false zurück, ausser wenn ich die gleichen Instanzen vergleiche:
    str==str=true;
    str==str4=false;

    beide haben aber selben inhalt (hallo)



  • Man.bloed schrieb:

    hab doch schon ganz am anfang gesagt was nich geht:
    Operator +:

    MeinString str("hallo");
    MeinString str2("test");
    MeinString str4("hallo");
    MeinString str3=str+str2;
    

    da wird nicht nur aus str3 hallotest, sondern auch aus str (aber str soll sich ja nich verändern)

    Und was erwartest du, wenn du

    char* chr1 = strcat(chr,rhs.chr);
    

    schreibst? Ich hoffe dir ist klar, dass du damit die aktuelle Instanz veränderst. Mit const-correctness wäre das übrigens nicht passiert.
    Aber um's kurz zu machen, Shade hat ja schon ein Beispiel gepostet, wie das im Prinzip aussieht. Du erstellst eine temporäre Instanz, hängst den rechten Operanden ran und gibst diese by-value zurück. Und mit entsprechendem copy-ctor funktioniert das dann auch problemlos.

    const MeinString operator +(const MeinString& lhs, const MeinString& rhs)
    {
        MeinString tmp(lhs);
        tmp += rhs;
        return tmp;
    }
    

    Fehlt nur noch der entsprechende Assignment-Operator, aber das wirst du schon hinbekommen. Der Funktionsrumpf sieht wie folgt aus

    MeinString& operator +=(const MeinString& rhs)
    {
        //...
        return *this;
    }
    

    Auf diese Art und Weise lassen sich übrigens alle verknüpfenden Operatoren (+,-,*,/,%,&,|,^) implementieren.

    edit:
    Rückgabewert von operator + korrigiert.



  • Shade Of Mine schrieb:

    Foo operator+(Foo const& other)
    {
      Foo temp(other);
      temp+=*this;
      return temp;
    }
    
    Foo operator+(Foo const& a,Foo const& b)
    {
      Foo temp(a);
      temp+=b;
      return temp;
    }
    

    ok 😕 😕 😕



  • Shades Beispiel war aber innerhalb der Klasse. Bin mir zwar jetzt nicht ganz sicher, was er wollte (bis auf des fehlende const). Aber er macht in Wirklichkeit b + a, obwohl es a + b sein müsste.



  • groovemaster schrieb:

    Shades Beispiel war aber innerhalb der Klasse. Bin mir zwar jetzt nicht ganz sicher, was er wollte (bis auf des fehlende const). Aber er macht in Wirklichkeit b + a, obwohl es a + b sein müsste.

    Ja, ich wollte auf das const hinaus.

    das mit b+a war ein Fehler von mir 😞 hab nicht genau nachgedacht und nach sturer gewohnheit den 1. parameter als lhs angenommen und ohne nachzudenken wurde dann this zum rhs.

    dumm von mir 😞



  • Wenn schon const-correctnes dann auch richtig:

    const Foo operator+(Foo const& a,Foo const& b)
    {
      Foo temp(a);
      temp+=b;
      return temp;
    }
    


  • Eine lokale Variable darf doch eh nicht verändert ewrden oder seh ich da was falsch?



  • hm...irgendwie bekomm ich das nich hin!
    Also die operatoren ausserhalb der klasse?

    Wenn ja, wie greife ich auf die private objekte zu? (also mein charzeiger)?



  • Schau dir mal das Schlüsselwort friend an, dies ermöglicht es dir auch auf private Elemente außerhalb der Klasse zuzugreifen.

    http://www.cpp-tutor.de/cpp/le12/le12_04.htm#logisch

    PS: Warum hat es hier solange gedauert, bis mal jemand auf die eigentliche Frage von Man.bloed eingegangen ist? 😕



  • danke....
    nun habe ich aber gehört...friend soll man nicht nehmen?


Anmelden zum Antworten