+ Operator überladen! Funktioniert nicht ganz



  • Hallo,

    also hier mein quellcode!
    meine fragen und das problem hab ich als kommentar gekennzeichnet, hoffe ihr könnt mir helfen!

    class Haus
    {
     public:
      //Konstruktore
      Haus()         //kann man so standardwerte initialisieren, wenn nix eingegeben wird, oder lieber einen konstruktor mit default-parametern?
      {
       mAnzahlR=3;
       mFlaeche=100;
       mAnzahlT=3;
       mName = new char[25];
       strcpy(mName,"Standardhaus");
       mAnzahlH++;
      }
      Haus(int rooms,int space,int doors,const char* name)
      {
       mAnzahlR=rooms;
       mFlaeche=space;
       mAnzahlT=doors;
       mName = new char[strlen(name)+1];
       strcpy(mName,name);
       mAnzahlH++;
      }
      Haus(const Haus& anderes)
      {
       mAnzahlR = anderes.mAnzahlR;
       mFlaeche = anderes.mFlaeche;
       mAnzahlT = anderes.mAnzahlT;
       mName = new char[strlen(anderes.mName)+1];   //richtig?
       strcpy(mName,anderes.mName);
       mAnzahlH++;
      }
      ~Haus()
      {
       delete[] mName;
       mName=0;                 //nötig,und wenn ja richtig?
       mAnzahlH--;
      }
      //Static -Funktionen
      static int HausAnzahl(){return mAnzahlH;}
    
      //Operatoren
      Haus operator+(Haus& rhs)
      {
       Haus summe(*this);        //ruft copy-konstruktor auf
       summe.mAnzahlR+=rhs.mAnzahlR;
       summe.mFlaeche+=rhs.mFlaeche;
       summe.mAnzahlT+=rhs.mAnzahlT;
       return summe;
      }
      //Get - Methoden
      int GetAnzahlRaeume()const{return mAnzahlR;}
      int GetGesamtFlaeche()const{return mFlaeche;}
      int GetAnzahlTueren()const{return mAnzahlT;}
      char* GetName()const{return mName;}
     private:
      int mAnzahlR;
      int mFlaeche;
      int mAnzahlT;
      char* mName;
      static int mAnzahlH;
    };
    
    int Haus::mAnzahlH = 0;
    void PrintHaus(Haus& h)
    {
     cout<<"Hausname: "<<h.GetName()<<endl;
     cout<<"Raeume: "<<h.GetAnzahlRaeume()<<endl;
     cout<<"Flaeche: "<<h.GetGesamtFlaeche()<<endl;
     cout<<"Tueren: "<<h.GetAnzahlTueren()<<endl;
    }
    int main(int argc, char* argv[])
    {
     Haus a(5,300,3,"Test");
     Haus b(4,100,2,"Test2");
     Haus c = a + b;      //geht
    
     Haus d;
     d = a + b;           //geht nicht??   (Name wird bei PriontHaus(d) nicht angezeigt, und Programm hängt)
    
     PrintHaus(c);
     PrintHaus(d);
     getch();       return 0;
    }
    


  • Du brauchst noch einen vernünftigen operator=, damit der Code funktionieren kann - der vom Compiler bereitgestellte kommt nicht mit dynamischen Membern zurecht (damit zeigt d.mName im Endeffekt auf den Speicher, den der Dtor von 'summe' bei Funktionsende bereinigt hat).



  • also ich hab das jetzt etwas angepasst, funktioniert auch soweit!
    Hätte nur gern bisschen kritik, was ich anders machen sollte, was fehlt, was gut ist, wo es probleme geben könnte!

    Das dies eine HAUS Klasse ist sollte nicht stören, war nur zum üben!
    darum vergleichen die vergleichsoperatoren natürlich nicht den name oder so

    mir geht es erstmal um das programmierprinzip, und den stil etc..und natürlich um fehler

    achso, und die mischung der namen (english/deutsch) tut mir leid, sollte aber erstmal nicht stören)

    also wer lust hat kann sich ja mal den ganzen code anschauen 🙂

    class Haus
    {
     public:
      //Konstruktore
      Haus()         //kann man so standardwerte initialisieren, wenn nix eingegeben wird, oder lieber einen konstruktor mit default-parametern?
      {
       mAnzahlR=3;
       mFlaeche=100;
       mAnzahlT=3;
       mName = new char[25];
       strcpy(mName,"Standardhaus");
       mAnzahlH++;
      }
      Haus(int rooms,int space,int doors,const char* name)
      {
       mAnzahlR=rooms;
       mFlaeche=space;
       mAnzahlT=doors;
       mName = new char[strlen(name)+1];
       strcpy(mName,name);
       mAnzahlH++;
      }
      Haus(const Haus& anderes)
      {
       mAnzahlR = anderes.mAnzahlR;
       mFlaeche = anderes.mFlaeche;
       mAnzahlT = anderes.mAnzahlT;
       mName = new char[strlen(anderes.mName)+1];   //richtig?
       strcpy(mName,anderes.mName);
       mAnzahlH++;
      }
      ~Haus()
      {
       delete[] mName;
       mName=0;                 //nötig,und wenn ja richtig?
       mAnzahlH--;
      }
      //Static -Funktionen
      static int HausAnzahl(){return mAnzahlH;}
    
      //Operatoren
      Haus operator+(Haus& rhs)
      {
       Haus summe(*this);        //ruft copy-konstruktor auf
       summe.mAnzahlR+=rhs.mAnzahlR;
       summe.mFlaeche+=rhs.mFlaeche;
       summe.mAnzahlT+=rhs.mAnzahlT;
       return summe;
      }
      Haus& operator=(const Haus& rhs)
      {
       if(this!=&rhs)
       {
       mAnzahlR = rhs.mAnzahlR;
       mFlaeche = rhs.mFlaeche;
       mAnzahlT = rhs.mAnzahlT;
       delete[] mName;
       mName = new char[strlen(rhs.mName)+1];
       strcpy(mName,rhs.mName);
       return *this;
       }
      }
      Haus& operator+=(const Haus& rhs)
      {
       mAnzahlR += rhs.mAnzahlR;
       mFlaeche += rhs.mFlaeche;
       mAnzahlT += rhs.mAnzahlT;
       return *this;
      }
      Haus& operator-=(const Haus& rhs)
      {
       mAnzahlR -= rhs.mAnzahlR;
       mFlaeche -= rhs.mFlaeche;
       mAnzahlT -= rhs.mAnzahlT;
       return *this;
      }
      bool operator<(const Haus& rhs)
      {
       bool ok = false;
       if(mAnzahlR < rhs.mAnzahlR)
        if(mFlaeche < rhs.mFlaeche)
         if(mAnzahlT < rhs.mAnzahlT)
          ok = true;
         return ok;
      }
      bool operator==(const Haus& rhs)
      {
       bool ok = false;
       if(mAnzahlR == rhs.mAnzahlR)
        if(mFlaeche == rhs.mFlaeche)
         if(mAnzahlT == rhs.mAnzahlT)
          ok = true;
         return ok;
      }
      //Get - Methoden
      int GetAnzahlRaeume()const{return mAnzahlR;}
      int GetGesamtFlaeche()const{return mFlaeche;}
      int GetAnzahlTueren()const{return mAnzahlT;}
      char* GetName()const{return mName;}
      //Set - Methoden
      void SetRaeume(int count)
      {
       if(count>0)
        mAnzahlR = count;
       else
        mAnzahlR = mAnzahlR;
      }
      void SetFlaeche(int space)
      {
       if(space>0)
        mFlaeche = space;
       else
        mFlaeche = mFlaeche;
      }
      void SetTueren(int doors)
      {
       if(doors>0)
        mAnzahlT = doors;
       else
        mAnzahlT = mAnzahlT;
      }
      //Extend - Methoden
      void VergroessereFlaeche(int morespace)
      {
       if(morespace>0)
        mFlaeche += morespace;
      }
      void NeueRaeume(int roomcount)
      {
       if(roomcount>0)
        mAnzahlR += roomcount;
      }
      void NeueTueren(int doorcount)
      {
       if(doorcount>0)
        mAnzahlT += doorcount;
      }
      //anderes
      void NameAendern(const char* newname)
      {
       delete[] mName;
       mName = new char[strlen(newname)+1];
       strcpy(mName,newname);
      }
     private:
      int mAnzahlR;
      int mFlaeche;
      int mAnzahlT;
      char* mName;
      static int mAnzahlH;
    };
    
    int Haus::mAnzahlH = 0;
    void PrintHaus(Haus& h)
    {
     cout<<"Hausname: "<<h.GetName()<<endl;
     cout<<"Raeume: "<<h.GetAnzahlRaeume()<<endl;
     cout<<"Flaeche: "<<h.GetGesamtFlaeche()<<endl;
     cout<<"Tueren: "<<h.GetAnzahlTueren()<<endl;
    }
    


  • Also wenn du einen Tipp haben willst, was du noch besser machen kannst, dann solltest du anstatt von "Print Haus" über einen operator<< nachdenken!

    ostream& operator<< (ostream& os,const Haus& haus);
    

    dann hast du später die Möglichkeit

    Haus h;
    cout << h;
    

    zu schreiben.


  • Mod

    operator+ sollte auf der rechten seite eine referenz auf const nehmen

    + < und == sollten const member sein

    + kann ohne weiteres direkt auf += von Haus aufbauen

    GetName() sollte ein const char* zurrückgeben zwecks logischer const-korrektheit

    operator= und NameAendern sind nicht exception-sicher, wenn das korrigiert wird, kannst du diese funktion direkt für op= verwenden und der test auf selbstzuweisung kann entfallen

    besser noch std::string statt char* verwenden, es vereinfacht die angelegenheit gewaltig

    das mName=0 im destruktor ist überflüssig

    der unterschied zwischen den Set... und den Neue...-funktionen entgeht mir



  • und der Zuweisungsoperator liefert nicht immer einen Wert zurück:

    operator=(const Haus& other)
    {
      if(this!=&other)
      {
        ...
        return *this;
      }
      //hier fehlt die Rückgabe !!
    }
    


  • camper schrieb:

    + kann ohne weiteres direkt auf += von Haus aufbauen

    macht er das nicht?
    vielleicht kannst mir das mit einem beispiel erklären?

    camper schrieb:

    operator= und NameAendern sind nicht exception-sicher, wenn das korrigiert wird, kannst du diese funktion direkt für op= verwenden und der test auf selbstzuweisung kann entfallen

    wieso sind sie das nicht?Auch hier wäre mir ein beispiel lieb

    camper schrieb:

    der unterschied zwischen den Set... und den Neue...-funktionen entgeht mir

    Die Set-Methoden setzen die Anzahl der Räume, und die Neue-Methoden addieren Räume, Fläche hinzu, setzen aber nix neu!

    @SALOMON: ja das werde ich mal versuchen
    @CStoll: was sollte da zurückgegeben werden?



  • ohmann?! schrieb:

    camper schrieb:

    + kann ohne weiteres direkt auf += von Haus aufbauen

    macht er das nicht?
    vielleicht kannst mir das mit einem beispiel erklären?

    Nein, er nutzt nur die selben Anweisungen. Typischerweise kannst du den op+ so schreiben:

    Haus::operator+(const Haus& rhs)
    {
      Haus tmp(*this);
      return tmp+=rhs;
    }
    

    @CStoll: was sollte da zurückgegeben werden?

    ebenfalls *this (oder noch besser - du schiebst den vorhandenen return eine Zeile nach unten (aus dem if()-Block raus))


  • Mod

    ohmann?! schrieb:

    camper schrieb:

    operator= und NameAendern sind nicht exception-sicher, wenn das korrigiert wird, kannst du diese funktion direkt für op= verwenden und der test auf selbstzuweisung kann entfallen

    wieso sind sie das nicht?Auch hier wäre mir ein beispiel lieb

    new könnte eine exception auslösen, den alten namen hast du dann aber schon gelöscht (und das führt spätestens im destruktor dann zum doppelten delete). weiterhin erhälst du UB, falls das argument von NameAendern gerade der name des objekts ist, also:

    Haus a;
    a.NameAenderna(a.GetName());
    

    beide probleme erschlägst du durch die richtige reihenfolge:

    void NameAendern(const char* newname)
    {
       chat* p = new char[strlen(newname)+1];
       strcpy(p,newname);
       delete[] mName;
       mName=p;
    }
    

    und dann ergibt sich op= folgerichtig als:

    Haus& operator=(const Haus& rhs)
    {
       mAnzahlR = rhs.mAnzahlR;
       mFlaeche = rhs.mFlaeche;
       mAnzahlT = rhs.mAnzahlT;
       NameAendern(rhs.GetName());
       return *this;
    }
    

    ungeachtet dessen bleibt der hinweis, besser std::string zu verwenden, bleibt weiterhin gültig (dann ist z.b. die definition von op= unnötig).



  • wieso muss im zuweisungsoperator mName delete[]et werden?
    wird ja im konstruktor auch nich gemacht!

    oder muss das garnicht gemacht werden?



  • Weil der Konstruktor ein neues Objekt konstruiert. Der Zuweisungsoperator weist einem schonmal konstruierten Objekt etwas neues zu, da muss das alte doch weg.


Anmelden zum Antworten