Verständnisfrage zum "=" Operator



  • Hallo, ich habe eine Frage:
    Wenn ich zum Beispiel folgende Klasse habe

    class Text
    {
       private:
        std::string text;
    
       public:
        Text(const char* name) : text(name) {};       //1. Konstruktor
        Text(const std::string& name) : text(name) {} //2. Konstruktor
        Text& operator = (const Text& objekt)         // = Operator
        {
            text=objekt.text;
            return *this;
        }
    };
    

    Jetzt kann ich - gemäß den Konstruktoren - ein Objekt der Klasse Text auf zwei Arten initialisieren:

    std::string a = "test";
    Text obj1(a);
    Text obj2("test");
    

    Allerdings funktionieren auch folgende zuweisungen:

    std::string a = "test";
    Text obj1=a;
    Text obj2="test";
    

    Ist der "=" Operator, der im zweiten Beispiel verwendet wird ein anderer, als der, den man Überladen kann? Denn in meiner Text-Klasse ist er nur als Kopierkonstruktor für andere Text-Objekte eingerichtet. Oder überlädt der Kompiler den "=" Operator am Beispiel der Konstruktoren automatisch, damit diese Zuweisungen funktionieren?



  • Erstens mal brauchst du weder Kopierkonstruktor noch Zuweisungsoperator für deine Klasse zu überladen. Eine memberweise Kopie ist ja gewünscht, und das machen die compilergenerierten Funktionen. Erst wenn du selber noch etwas tust (z.B. Deep Copy über Zeiger), brauchst du eigene Implementierungen.

    Zweitens sind jeweils

    Test obj1 = a;
    Test obj1(a);
    

    und

    Test obj1 = "test";
    Test obj1("test");
    

    äquivalent. Wenn das Gleichheitszeichen in der Initialisierung vorkommt, handelt es sich um einen Konstruktor- und keinen Zuweisungsoperatoraufruf. Somit kommt in deinem zweiten Beispiel nirgends ein operator= vor.



  • Deine Konstruktoren sind nicht "explicit", d.h. sie erlauben auch implizite Konvertierungen.
    D.h. es gehen dann auch solche Sachen:

    void foo(Text t)
    {
       // ...
    }
    
    void bar()
    {
        foo("sepp"); // hier wird implizit mit Test::Test(const char*) ein Objekt erzeugt,
                     // und dieses dann mit dem vom Compiler erstellten copy-ctor kopiert, um es an foo() zu übergeben
    }
    

    Genau dasselbe wie oben passiert in deinem Beispiel: es wird erst über dem Konstruktor ein neues Objekt erzeugt, und dieses dann mit dem operator = zugewiesen.

    Wenn du das nicht haben möchtest, musst du die Konstruktoren 'explicit' machen:

    class Text
    {
       private:
        std::string text;
    
       public:
        explicit Text(const char* name) : text(name) {};       //1. Konstruktor
        explicit Text(const std::string& name) : text(name) {} //2. Konstruktor
        Text& operator = (const Text& objekt)         // = Operator
        {
            text=objekt.text;
            return *this;
        }
    };
    

    Grundsätzlich kann man sagen: vor jeden Konstruktor erstmal "explicit" schreiben, und nur dann ändern, wenn man *wirklich* implizite Konvertierungen erlauben will.



  • hustbaer schrieb:

    und dieses dann mit dem operator = zugewiesen.

    Ich gehe mal von einem Flüchtigkeitsfehler aus, weil es in deinem Code ja anders steht. 😉

    Wie Nexus schon bemerkte ist der Operator = bei den Initialisierungen nicht involviert sondern Konstruktor + Copy-Konstruktor bzw. optimiert nur der Konstruktor.



  • Kritiker schrieb:

    hustbaer schrieb:

    und dieses dann mit dem operator = zugewiesen.

    Ich gehe mal von einem Flüchtigkeitsfehler aus, weil es in deinem Code ja anders steht. 😉

    Wie Nexus schon bemerkte ist der Operator = bei den Initialisierungen nicht involviert sondern Konstruktor + Copy-Konstruktor bzw. optimiert nur der Konstruktor.

    Ja, du hast recht 🙂


Anmelden zum Antworten