Zeiger/Referenz bei Operatoren



  • Ich habe folgenden Code:

    template<typename T>
    class Array
    {
        public:
            T* operator[](int index)
            {
                return ...;
            }
    
    };
    
    int main(...)
    {    
        Array<int> *a = new Array<int>();
        //fülle a
        std::cout << *(*a)[1] << std::endl;
    
        Array<int> b;
        //fülle b
        std::cout << b[1] << std::endl;
        return 0;
    }
    

    Nun meine Frage dazu: Arbeiten die Operatoren immer auf Objekten, also nicht auf Zeigern? Muss ich dafür sorgen, dass ich niemals einen Operator auf einen Zeiger anwende? Also etwa:

    Array<int> *a = new Array<int>();
    //fülle a
    std::cout << a[1] << std::endl;
    

    Inwiefern liege ich falsch?



  • Du kannst zurückgeben, was immer du willst 😉 Nur mußt du auf der anderen Seite wissen, wie du damit umzugehen hast.

    PS: "Normale" Operatoren geben übrigens Referenzen (oder konstante Referenzen) oder Objekte zurück.



  • Marc++ schrieb:

    Nun meine Frage dazu: Arbeiten die Operatoren immer auf Objekten, also nicht auf Zeigern?

    Ja (bzw. auf Referenzen). Zeiger sind eingebaute Datentypen und haben fest definierte Operatoren (*, ->, [], +, -, ++, -- usw.).

    Muss ich dafür sorgen, dass ich niemals einen Operator auf einen Zeiger anwende? Also etwa:

    Array<int> *a = new Array<int>();
    //fülle a
    std::cout << a[1] << std::endl;
    

    Ich verstehe die Frage nicht ganz, aber ich kann dir erklären, was dein Code macht: Da a ein Zeiger ist, ist a[1] ein ganz normaler Array-Zugriff. Nun ist das dahinterliegende "Array" aber lediglich von der Länge 1, dein Zeiger zeigt nur auf eine Instanz vom Typ Array<int>, so dass obige Code undefiniertes Verhalten zeigt (BTW es ist ein bisschen verwirrend, dass hier "Array" in zwei Bedeutungen auftaucht. Ich hoffe du kommst damit klar, schließlich ist das auf deinem Mist gewachsen :p ).
    Wenn du den von deiner Klasse überladenen operator[] ansprechen willst, musst du wie gehabt a dereferenzieren: (*a)[1].



  • Ich glaube ich habe mich unverständlich ausgedrückt. Ich habe mir mal ein anderes Beispiel überlegt:

    #include <iostream>
    #include <ostream>
    #include <string>
    
    class Complex
    {
        public:
            double re;
            double im;
    
            Complex(double re=0, double im=0)
                : re(re), im(im) {}
    
            ~Complex(){}
    
            Complex operator+(const Complex &rval)
            {
                Complex c(re+rval.re, im+rval.im);
                return c;
            }
    
            Complex operator+(const Complex *rval)
            {
                Complex c(re+rval->re, im+rval->im);
                return c;
            }
    };
    
    std::ostream& operator<<(std::ostream &os, Complex &c)
    {
        os << "re: " << c.re << ", im: " << c.im;
        return os;
    }
    
    int main(int argc, char **argv)
    {
        Complex c1(10,50);
        Complex c2(2, 5);
    
        c1 = c1 + c2;
        std::cout << c1 << std::endl;
    
        Complex *c3 = new Complex(100, 200);
        c1 = c2 + c3;
        std::cout << c1 << std::endl;
    
        c1 = c3 + c3;   //Fehler! c3 + c2 dürfte ebenfalls nicht gehen!
        std::cout << c1 << std::endl;
        return 0;
    }
    

    Wenn ich das richtig sehe, habe ich keine Möglichkeit einen einen Op auf einem Zeiger operieren zu lassen. Also das die linke Seite des Operators ein Zeiger ist.

    Ich hoffe diesesmal habe ich es verständlicher ausgedrückt. 🙂



  • Doch, du könntest schon, solltest jedoch nicht:

    Complex Complex::operator+(Complex* other)
    {...}
    
    ...
    Complex c1,c2;
    Complex c3 = c1 + &c2; //benötigt "&", um einen Complex* zu bekommen
    

    Um als linken Operand einen Zeiger zu verwenden, benötigst du eine globale Funktion.

    PS: Und mindestens einer der Operanden muß ein User-definierter Typ sein, sonst kommst du in Konflikt mit den integrierten Operatoren.



  • Meine Fragen hören leider nicht auf, aber ich hoffe ich habe alles verstanden!

    Ich habe die Complex Klasse eben nocheinmal erweitert:

    #include <iostream>
    #include <ostream>
    #include <string>
    
    class Complex
    {
        public:
            double re;
            double im;
    
            Complex(double re=0, double im=0)
                : re(re), im(im) {}
    
            ~Complex(){}
    
            Complex operator+(const Complex &rval)
            {
                Complex c(re+rval.re, im+rval.im);
                return c;
            }
    
            Complex operator*(const Complex &rval)
            {
                Complex c(re*rval.re, im*rval.im);
                return c;
            }
    
            Complex& operator++()
            {
                ++re;
                ++im;
                return *this;
            }
    
            Complex operator++(int dummy)
            {
                Complex c = *this;
                ++re;
                ++im;
                return c;
            }
    };
    
    std::ostream& operator<<(std::ostream &os, Complex &c)
    {
        os << "re: " << c.re << ", im: " << c.im;
        return os;
    }
    
    int main(int argc, char **argv)
    {
        Complex c1(10,50);
        Complex c2(2, 5);
    
        c1 = c1 + c2;
        std::cout << "c1 + c2 = " << c1 << std::endl;
    
        c1 = c1 * c2;
        std::cout << "c1 * c2 = " << c1 << std::endl;
    
        std::cout << "++c1 = " << ++c1 << std::endl;
        std::cout << "c1++ = " << c1++ << std::endl;    //Warum klappt das nicht?
        std::cout << "nach c1++ = " << c1 << std::endl;
    
        return 0;
    }
    

    Ich habe mich auch nochmal mit den unären Operatoren auseinander gesetzt. Soweit so gut. Jedoch erhalte ich den oben kommentierten Fehler. Nur frage ich mich warum? Ich gebe von dem Objekt eine Kopie zurück, da in dieser Form der Inkrement ja erst nach der Rückgabe erfolgt. Dem op<< dürfte es doch ziemlich egal sein, ob ++ eine Referenz oder ein Objekt zurückgegeben hat?!?

    Danke! 🙂



  • Du kannst keine nicht-const-Referenz an ein temporäres Objekt binden. Das ist hier aber auch gar nicht notwendig, deklarier den zweiten Parameter im operator<< doch als const-Referenz.

    (über den Unsinn eines operator++ in einer Klasse für komplexe Zahlen sag ich jetzt lieber nichts)


Anmelden zum Antworten