Operatoren überladen



  • Hallo,

    ich bin gerade dabei mich mit dem Überladen von Operatoren zu beschäftigen. Ich hab dazu mal die "Standardklasse" Bruch geschrieben die folgendermassen aussieht:

    class Bruch
    {
      friend  Bruch operator*( Bruch b1, Bruch b2); 
     private:
              int mz,mn;
     public:
              Bruch(int z=0,int n=1);
              void display();
    };
    
    ...
     Bruch operator *( Bruch b1, Bruch b2)
    {
      Bruch erg;
      erg.mz=b1.mz*b2.mz;
      erg.mn=b1.mn*b2.mn;
      return erg;
    }
    

    den Operator hab ich also außerhalb der Klasse überladen damit ich nicht nur zwei Brüche multiplizieren kann sondern auch einen Bruch mit einer int Zahl. Das funktioniert auch, aber wenn ich statt der Parameter vom Typ Bruch eine Referenz auf Bruch verwende funktioniert es nicht:

    Bruch operator *( Bruch& b1, Bruch& b2)
    {...}
    

    (hab ich natürlich auch so in der Header deklariert)
    es entsteht der Fehler

    [C++ Fehler] Unit1.cpp(8): E2094 'operator*' ist im Typ 'Bruch' für Argumente des Typs 'int' nicht implementiert
    

    schreibe ich allerdings ein

    const
    

    davor geht's wieder:

    Bruch operator *(const Bruch& b1,const Bruch& b2)
    {...}
    

    jetzt könnte ich mir ja merken, daß es halt so funktioniert, aber ich begreife es nicht 😞 . Kann mir jemand erklären wieso das alles so ist? 😕

    Ich hab übrigens schon ziemlich viel nachgesucht aber nichts befriedigendes gefunden.

    Danke schon mal 🙂

    Ebi



  • Also ich würde sagen Compilerbug, denn bei mir (Compiler: Borland C++ 5.5.1) funktionieren alle Varianten (Compiler)-Fehlerfrei.

    Ich würde dir empfehlen, eventuelle Updates herunterzuladen...

    Caipi



  • Warum willst du die überhaupt nicht const haben? Macht doch nicht viel Sinn, die zu bearbeiten, dann hättest du nicht das normale verhalten von operator* oder erwartest du, dass wenn du schreibst: a = b*c, dass sich dann b oder c verändern? Nur so am Rande :p
    Ansonsten könntest du aber auch mal versuchen, die Funktion innerhalb der Klasse zu überladen oder ein Template mit explizierter Instanzierung zu nutzen, dann bräuchtest du nicht für jeden Typ die Funktion überladen und halt nur für die Klasse Bruch beispielweise das ganze explizit Instazieren.
    So, nu ein frohes neues Jahr *Party* 😉

    PS: Warum gibts keine Smiley mit Rakete oder so :p



  • class Foo
    {
       int i_;
    public:
       Foo (int i) : i_(i) {}
       int value () const { return i_; }
    };
    
    Foo operator + (Foo& r, Foo& l)
    {
       return r.value() + l.value();
    }
    
    int main ()
    {
       Foo x(2);
       Foo f = x + 3;
    }
    

    das funktioniert bei dir?

    @Ebi01:
    (vereinfacht gesagt) der grund dafür liegt an der konstruktion von einem temporären objekt, das nur an eine konstante referenz gebunden werden kann.



  • Ich denke ich würd das ca. so machen:

    class Bruch { 
    private: 
        int mz,mn; 
    public: 
        Bruch(int z=0, int n=1):mz(z), mn(n) {}
    
        int getZ() const { return mz; }
        int getN() const { return mn; }
        void display() const; 
    }; 
    
    ... 
    
    const Bruch operator *(const Bruch& b1,const Bruch& b2) { 
        Bruch erg(b1.getZ()*b2.getZ(), b1.getN()*b2.getN());
        return erg; 
    }
    


  • ist ja ganz nett, aber ich kann immer wieder nur mit dem antworten:
    http://tutorial.schornboeck.net/operatoren_ueberladung.htm



  • davie schrieb:

    class Foo
    {
       int i_;
    public:
       Foo (int i) : i_(i) {}
       int value () const { return i_; }
    };
    
    Foo operator + (Foo& r, Foo& l)
    {
       return r.value() + l.value();
    }
    
    int main ()
    {
       Foo x(2);
       Foo f = x + 3;
    }
    

    das funktioniert bei dir?

    @Ebi01:
    (vereinfacht gesagt) der grund dafür liegt an der konstruktion von einem temporären objekt, das nur an eine konstante referenz gebunden werden kann.

    @davie
    Nein, das nicht, aber das:

    class Foo
    {
       int i_;
    public:
       Foo (int i) : i_(i) {}
       int value () const { return i_; }
    };
    
    Foo operator + (Foo& r, Foo& l)
    {
       return r.value() + l.value();
    }
    
    int main ()
    {
       Foo x(2), y(4);
       Foo f = x + y;
    }
    

    Und nachdem das in allen Varianten funktioniert hat (übertragen auf Ebi01's Beispiel), hab ich irgendwie vergessen es noch mit Konstanten zu überprüfen [...]. Danke für deine Korrektur!

    @Ebi01
    Sorry für meinen vorigen Post bzw. meine Falschinformation, doch kein Compilerbug. 🙂 (Woher kam doch gleich der Spruch: "95% aller Fehler sitzen ca. 60 cm vor dem Bildschirm [...] )

    Caipi



  • abgesehen davon dass es mit nicht const referenzen ja nicht funktioniert, machen non const referenzen hier ja auch garkeinen sinn.

    sie sagen naemlich, dass der op* die brueche aendern darf - was ich persoenlich doch fuer komisch halte...



  • Vielen dank erst mal für die vielen Antworten. Ich gebe euch recht, daß bei dem Problem nicht const Referenzen wenig Sinn machen. Mir geht es halt vor allem darum zu begreifen was dahinter steckt.
    @Caipi

    @Ebi01:
    (vereinfacht gesagt) der grund dafür liegt an der konstruktion von einem temporären objekt, das nur an eine konstante referenz gebunden werden kann.

    kannst du mir da noch erklären weshalb das so ist? Ich glaub fast mir fehlt in dem Bereich das Hintergrundwissen.

    Danke schon mal

    Ebi



  • Ebi01 schrieb:

    kannst du mir da noch erklären weshalb das so ist? Ich glaub fast mir fehlt in dem Bereich das Hintergrundwissen.

    Wenn du einen Ctor hast, der nicht "explicit" ist, dann kann der Compiler diesen zum Unwandeln verwenden.

    Wenn wir nun eine Klasse Foo haben:

    class Foo
    {
    public:
      Foo(int){}
    };
    

    Dann kann der Compiler einen int in Foo umwandeln:

    void f(Foo){}
    
    f(2);
    

    Nur ist diese Umwandlung ein temporaeres Objekt. Denn es ist das selbe wie:

    f(Foo(2));
    

    Auf temporaere Objekte darf man keine non const Referenz haben. Deshalb kann f() das Foo hier nicht per Referenz sondern nur entweder by value oder by const reference nehmen.



  • (achtung, passt nur mehr bedingt dazu)

    Shade Of Mine schrieb:

    Auf temporaere Objekte darf man keine non const Referenz haben.

    was bei temporären objekten ganz lustig ist, da sie eigentlich nicht const sind.

    struct Foo
    {
       Foo (int) {}
       Foo& lvalue () { return *this; }
    };
    
    void bar (Foo &)
    {
    }
    
    int main ()
    {
       bar (Foo(2).lvalue());
    }
    

    zeigt wieder einmal die wunderbaren möglichkeiten, die dir c++ bietet [achtung]

    //edit: ärger ausschlafen, duschen und dann schreiben.



  • Danke vor allem an Shade of Mine. Das klingt für mich ziemlich plausibel. Jetzt nur nochmal ob ich das richtig verstanden hab. Da der Konstruktor nur ein temporäres Objekt anlegt und eigentlich auch sofort wieder zerstört würde es eine Referenz auf ein nicht mehr gültiges Objekt geben. Was passiert dann mit dem Objekt wenn const davor steht. Heißt das, daß es nicht sofort zerstört wird? 😕

    Ebi


Anmelden zum Antworten