operatoren überladen



  • hallo...
    ich suche eine liste oder ähnliches, wo drin steht, welchen rückgabetyp der standard bei den verschiedenen operatoren vorschreibt/empfiehlt...

    also ob = nix zurückgibt (also void) oder doch nen bool zurückgeben sollte etc...

    Danke schon mal : )



  • Wenn du Operatoren für eigene Datentypen (Klassen) überladen willst, kommt es darauf an, wozu du sie benötigst. Hier ein paar Standardbeispiele:

    Der Zugriffsoperator [] (z.B. bei Containern) gibt normalerweise eine konstante Referenz zurück.

    Bei arithmetischen (unären und binären) Operatoren (global; +, -, *, /, %; als Methode +=, -=, *=, /=, %=; unär als Vorzeichen +, -) gibst du meistens eine Kopie eines temporär erzeugten Objekts zurück. Je nach Anwendung kannst du das auch bei && und || oder evtl. &, |, ^, ~ tun.

    Vergleichsoperatoren (==, !=, <, <=, >, 😆 geben normalerweise bool zurück, weil ja ein Wahrheitswert erwartet wird.

    Bei Zuweisungen ist der Rückgabetyp eine Referenz auf das neue Element, damit auch Mehrfachzuweisungen ( A = B = C; )möglich sind:

    class MyClass
    {
    private:
    	int x;
    public:
    	MyClass& operator = (const MyClass& Origin);
    };
    
    MyClass& MyClass::operator = (const MyClass& Origin)
    {
    	x = Origin.x;
    	return *this;  // Rückgabe: Referenz auf diese Instanz
    }
    

    Natürlich gibt es noch viel mehr Operatoren, aber ich denke, diese werden am meisten überladen, und bei einigen kenn ich mich auch nur schlecht aus 😉
    Ausserdem bist du da auch ziemlich frei, was die Überladungen betreffen. Der Rückgabetyp hängt eben davon ab, was du mit dem Operator erreichen willst.



  • Danke - aus deiner Antwort schließ ich jetzt einfach mal, dass du es auch immer so machst, wie du gerad denkst und wozu du lust hast bzw was du brauchst und im standard darüber keine angaben gemacht werden ^^

    klasse anleitung btw 👍

    bb



  • unskilled schrieb:

    Danke - aus deiner Antwort schließ ich jetzt einfach mal, dass du es auch immer so machst, wie du gerad denkst und wozu du lust hast bzw was du brauchst und im standard darüber keine angaben gemacht werden ^^

    Naja, wenn du das nur bei eigenen kleinen Klassen machst, geht z.B. void operator= noch, aber ich würd das bei diesem Beispiel von Anfang an mit Referenzrückgabe machen. Was die anderen Operatoren betrifft, ist es wohl am besten, wenn du sie so überlädst, wie man es erwartet. Also z.B. operator+ für die Addition und Rückgabe eines Objektes mit dem gleichen Typ wie die Operanden. Aber im Standard gibt es keine Vorgaben bezüglich Rückgabetyp, allerdings bezüglich Operandenzahl, Priorität und Assoziativität der Operatoren.

    unskilled schrieb:

    klasse anleitung btw 👍

    Vielen Dank 🙂



  • unskilled schrieb:

    Danke - aus deiner Antwort schließ ich jetzt einfach mal, dass du es auch immer so machst, wie du gerad denkst und wozu du lust hast bzw was du brauchst und im standard darüber keine angaben gemacht werden ^^

    klasse anleitung btw 👍

    bb

    Natürlich gibts dafür best Practises. Aber Vorschriften gibt es keine. Lies einfach die Standard-C++ Bücher die sich mit sauberem C++ Design auseinandersetzen dann weißt du schon was man machen soll was nicht und warum und weshalb und dann kannst du dir bei den restlichen Fällen leicht überlegen was man tun sollte.



  • Mal angenommen, ich habe einfach nichts darüber gefunden (weil ich zu doof zum googlen bin oder wie au immer)...

    Und bevor ich meine Operatoren einfach weiter nach belieben überlade frag ich einfach mal...

    Z.bsp. finde ich nicht, dass += eine Referenz wiedergeben sollte - denn wie oft benutzt man schon Konstrukte á la:

    A = B += C;
    

    Oder optimiert das der Kompiler auch raus?

    struct bla
    {
    int var;
    bla (int _var) : var (_var) {};
    void operator = (const bla &other) {var = other.bla;};
    void operator += (const bla &other) {var += other.bla;};
    };
    
    //...
    
    bla A, B, C;
    B = C; A = B;
    B += C;
    A = B;
    
    struct bla2
    {
    int var;
    bla (int _var) : var (_var) {};
    const bla& operator = (const bla &other) {var = other.bla; return *this;};
    const bla& operator += (const bla &other) {var += other.bla; return *this;};
    };
    
    //...
    
    bla2 A, B, C;
    A = B = C;
    A = B += C;
    

    ist das gleichschnell?

    Und:

    bla2 A (2), B (2), C (2);
    bla D (2), E (2), F (2);
    
    A += B;
    D += E;
    

    ist das auch gleichschnell?

    bb



  • Ich hab mal ein kleines Benchmark mit deinem Code (nach Korrektur der Fehler :p) geschrieben ( sf::Clock ist dabei eine Zeitklasse meiner Grafikbibliothek, die die Zeit in Sekunden seit Reset() oder dem Konstruktoraufruf zählt):

    struct bla 
    { 
    int var; 
    bla() {};
    void operator = (const bla &other) {var = other.var;}; 
    void operator += (const bla &other) {var += other.var;}; 
    }; 
    
    struct bla2 
    { 
    int var; 
    bla2() {};
    const bla2& operator = (const bla2 &other) {var = other.var; return *this;}; 
    const bla2& operator += (const bla2 &other) {var += other.var; return *this;}; 
    }; 
    
    int main()
    {
    	bla A, B, C; 
    	bla2 D, E, F;
    
    	long long int n = 100000000000;
    	sf::Clock Clock;
    	for (long long i = 0; i < n; i++)
    	{
    		B = C; A = B; 
    		B += C; 
    		A = B; 
    	}
    	std::cout << Clock.GetElapsedTime() << std::endl;
    	Clock.Reset();
    	for (long long i = 0; i < n; i++)
    	{
    		D = E = F; 
    		D = E += F; 
    	}
    	std::cout << Clock.GetElapsedTime() << std::endl;
    	std::cin.get();
    }
    

    Ausgabe bei 3 Programmaufrufen:

    105.299
    108.389
    
    110.77
    107.935
    
    109.273
    107.194
    

    Der Unterschied macht also nicht wirklich viel aus. Eine Referenz zurückzugeben ist ja auch nicht wahnsinnig zeitintensiv. Da gibt es meistens bessere Orte, um Optimierungen anzubringen. Und denke daran: Es sind 100 Milliarden Aufrufe oben 😉
    Ich selber wäre bereit, den kleinen Performanceverlust (ist es überhaupt einer?) für einen grösseren Anwendungsbereich in Kauf zu nehmen.



  • Ok, dann haste mich jz wo doch gerad so überzeugt ^^

    Danke : >


Anmelden zum Antworten