überladen des Operators scheitert... wo steckt der Fehler?



  • Hallo - hab da ne fräg!

    Also folgendes:

    Ich versuche den Operator == zu überlagern.
    Hab meine Klasse CEie. Wenn ich nun zwei Objekte miteinander vergleichen möchte, sollte das so aussehen:

    if(obj1==obj2)
    {
    return true;
    }
    else
    {
    return false;
    }
    

    Meine überladene Funktion schaut so aus:

    // überladene Operatoren
    bool CEie::operator == (CEie &obj)
    {
    	if(	this->get_wortdeutsch==obj.get_wortdeutsch() && this->get_wortenglisch==obj.get_wortenglisch() && 
    		this->get_satz1()==obj.get_satz1() && this->get_satz2()==obj.get_satz2() && this->get_kommentar==obj.get_kommentar)
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    
    }
    // Ende überladene Operatoren
    

    Die Deklarierung in der Klasse so:

    // Eie überladene Operatoren
    	bool operator== (CEie &obj);
    

    Leider kommt immmer folgende Fehlermeldung:

    h:\berweger\eie\eie_036_weitermachen\eie_methoden.cpp(618) : error C2679: Binaerer Operator '==' : Kein Operator definiert, der einen rechtsseitigen Operator vom Typ 'class CEie' akzeptiert (oder keine geeignete Konvertierung moeglich)
    h:\berweger\eie\eie_036_weitermachen\eie_methoden.cpp(628) : error C2678: Binaerer Operator '==' : Kein Operator definiert, der einen linksseitigen Operator vom Typ '' akzeptiert (oder keine geeignete Konvertierung moeglich)
    h:\berweger\eie\eie_036_weitermachen\eie_methoden.cpp(628) : error C2678: Binaerer Operator '==' : Kein Operator definiert, der einen linksseitigen Operator vom Typ '' akzeptiert (oder keine geeignete Konvertierung moeglich)
    Fehler beim Ausführen von cl.exe.
    

    😡

    Was ist falsch?

    Merci für die Hilfe!



  • Sollte wohl heißen

    bool CEie::operator == (CEie &obj) 
    { 
        if(    this->get_wortdeutsch()==obj.get_wortdeutsch() && this->get_wortenglisch()==obj.get_wortenglisch() &&  
            this->get_satz1()==obj.get_satz1() && this->get_satz2()==obj.get_satz2() && this->get_kommentar()==obj.get_kommentar()) 
        { 
            return true; 
        } 
        else 
        { 
            return false; 
        } 
    
    }
    

    Sind obj1 und obj2 beide vom Typ Eie oder Eie& ?

    normalerweise macht man das aber so:

    class Eie {
      friend bool operator == (const Eie&, const Eie&); //das const halt nur, wenn man nur konstante memberfunktionen verwendet.. also im normalfall schon
    };
    
    bool operator == (const Eie &bla, const Eie &blub) {
       return bla.get_x () == blub.get_x() && bla.get_y() == blub.get_y();
    }
    


  • davie schrieb:

    class Eie { 
      friend bool operator == (const Eie&, const Eie&); //das const halt nur, wenn man nur konstante memberfunktionen verwendet.. also im normalfall schon 
    }; 
     
    bool operator == (const Eie &bla, const Eie &blub) { 
       return bla.get_x () == blub.get_x() && bla.get_y() == blub.get_y(); 
    }
    

    Nicht ganz.
    Wenn man den operator== als friend deklariert, kann man sich die get??-Methoden sparen und direkt die Membervariablen ansprechen.



  • Oder andersrum gesagt: Wenn man nicht aus irgendwelchen exotischen Gründen direkten Zugriff auf die Membervariablen braucht, sollte man sich den friend sparen.



  • Der Meinung bin ich nicht. In so einer Situation ist friend sehr sinnvoll.

    Was wäre denn die Alternative? Für jede Membervariable eine get-Methode?



  • da gehen die geister auseinander 😃
    aber wenn es schon passende get methoden gibt, benutze ich die auch. auch das rädchen muss man nicht neu erfinden. ist aber imho geschmackssache



  • aber wenn es schon passende get methoden gibt, benutze ich die auch.

    Machst du das auch, wenn die get-Methode aus mehr als einem return besteht?



  • Hmmm, also bei mir sind die Objekte, die ich mit == vergleiche, meistens eh relativ übersichtlich und haben nicht sonderlich viel Intimsphäre. Wo verwendet ihr denn konkret friends zum Vergleichen? *neugier*



  • ich mache es:
    wenn ich die implementierung nicht (mehr) kenne
    wenn das verhalten des objekts nach außen auf gleichheit geprüft werden soll, und nicht die interne repräsentation.
    aber wie immer: it depends



  • Ob zwei Objekte gleich sind hängt doch nicht immer von allen Membern ab. Oft ist es so, dass es genau von denen Abhängt, auf die man irgendwie lesend zugreifen kann. Dann macht man den operator== natürlich nicht zum Freund, sondern verwendet die Methoden. Erst wenn man Iplementationsspezifisches zur Überprüfung auf Gleichheit benötigt macht man den Operator zum Freund.



  • Ich bleibe dabei, dass friend in diesem Fall gut passt.

    Durch friend wird der operator== ja sowas wie eine "halbe" Methode. Ich meine damit eine Methode der Klasse, die aber nicht in der Klasse definiert ist und auch nicht so aufgerufen wird.

    Macht ihr das bei Methoden auch so, dass ihr immer get-Methoden aufruft?

    class Bruch
    {
      /* K'tor etc. */
      // Variante 1:
      operator double() const { return static_cast<double>(getZaehler()) / getNenner(); };
      // Variante 2:
      operator double() const { return static_cast<double>(Zaehler) / Nenner; };
    
    private:
      int Zaehler, Nenner;
    };
    

    Nehmt ihr also Variante 1?



  • Ich würde vermutlich Variante 2 verwenden, auch wenn Variante 1 einige Vortiele hat. Falls sich die implementierung irgendwie ändert, es aber weiterhin ein getNenner und getZaehler gibt, muss ich meinen operator double nicht anpassen, bei Variante 2 hingegen schon.

    Im beschreibenen Problem sähe es jedenfalls bei mir in etwa so aus:

    bool operator == (const CEie & lhs, const CEie & rhs)  
    {  
       return lhs.get_wortdeutsch()==rhs.get_wortdeutsch() 
          && lhs.get_wortenglisch()==rhs.get_wortenglisch() 
          && lhs.get_satz1()==rhs.get_satz1() 
          && lhs.get_satz2()==rhs.get_satz2() 
          && lhs.get_kommentar()==rhs.get_kommentar();
    }
    


  • Helium schrieb:

    Ich würde vermutlich Variante 2 verwenden, auch wenn Variante 1 einige Vortiele hat. Falls sich die implementierung irgendwie ändert, es aber weiterhin ein getNenner und getZaehler gibt, muss ich meinen operator double nicht anpassen, bei Variante 2 hingegen schon.

    Wenn sich die Implementierung dahingehend ändert, dass es keine variable Zaehler und Nenner mehr gibt, muss man beide Varianten ändern.
    Die Variante 1 muss (oder sollte) deswegen geändert werden, weil in diesem Fall getZaehler/getNenner ziemlich sicher viel komplizierter als "return Zaehler;" sind.

    Wenn man z.B. den Bruch in einem einzigen double speichert (zwar blödsinn, aber mal rein theoretisch betrachtet).

    class Bruch
    {
    public:
      /* */
    
      // EntferneNachkommastellen multipliziert die Zahl so oft mit 10, bis alle Nachkommastellen weg sind
      int GetZaehler() const { return EntferneNachkommastellen(Ausgerechnet); }
      int GetNenner() const { return AnzahlNachkommastellen(Ausgerechnet) + 1.0; }
    
      // Variante 1:
      operator double() const { return static_cast<double>(GetZaehler()) / GetNenner(); }
      // Variante 2:
      operator double() const { return Ausgerechnet; }
    private:
      double Ausgerechnet;
    };
    

    Variante 1 ist die unveränderte aus dem obigen Posting. Die ist aber völlig schwachsinnig geworden.

    Wenn sich die interne Datendarstellung ändert, ist es nicht schlimm (sogar normal), wenn man viele oder sogar alle Methoden anpassen muss.



  • Die Variante 1 muss (oder sollte) deswegen geändert werden, weil in diesem Fall getZaehler/getNenner ziemlich sicher viel komplizierter als "return Zaehler;" sind.

    Na und? dennoch bleiben Sie unter garantie erhalten, da es bei einem Bruch nunmal extrem sinnvolle Methoden sind.

    Wenn sich die interne Datendarstellung ändert, ist es nicht schlimm (sogar normal), wenn man viele oder sogar alle Methoden anpassen muss.

    Das ist die richtige Einstellung. Arbtei ist was tolles. Ich ändere auch am liebsten tausendmal bereits funktionierenden Code. Vielleicht schleicht sich ja ein neuer Fehler ein. das wäre toll. Dan hätte ich endlich wieder was mehr Arbeit beim debuggen. Juchu!
    Wenn ich die interne Darstellung ändere, sollte sich nur der absolut grundlegenste Teil der Schnittstelle ändern müssen.



  • it depends ...


Anmelden zum Antworten