c++ - that - double operator c




Überladen von Mitgliedszugriffsoperatoren->,.*(C++) (4)

Ich verstehe die meisten Überladungen von Operatoren mit Ausnahme der Zugriffsoperatoren für Mitglieder -> .* , ->* usw.

Insbesondere was wird an diese Operatorfunktionen übergeben und was sollte zurückgegeben werden?

Wie weiß der Operator (z. B. operator->(...) ), auf welches Element Bezug genommen wird? Kann es das wissen? Muss es das überhaupt wissen?

Gibt es schließlich noch Überlegungen, die berücksichtigt werden müssen? Wenn Sie zum Beispiel etwas wie operator[] überladen, benötigen Sie normalerweise sowohl eine const als auch eine nicht-const-Version. Erfordern Mitgliedszugriffsoperatoren const und non-const Versionen?


->

Dies ist der einzige wirklich knifflige. Es muss eine nichtstatische Memberfunktion sein, die keine Argumente benötigt. Der Rückgabewert wird verwendet, um die Mitgliedersuche durchzuführen.

Wenn der Rückgabewert ein anderes Objekt des Klassentyps und kein Zeiger ist, wird die nachfolgende Membersuche auch von einer operator-> function gehandhabt. Dies wird als "Drilldown-Verhalten" bezeichnet. Die Sprache kettet die operator-> Aufrufe zusammen, bis die letzte einen Zeiger zurückgibt.

struct client
    { int a; };

struct proxy {
    client *target;
    client *operator->() const
        { return target; }
};

struct proxy2 {
    proxy *target;
    proxy &operator->() const
        { return * target; }
};

void f() {
    client x = { 3 };
    proxy y = { & x };
    proxy2 z = { & y };

    std::cout << x.a << y->a << z->a; // print "333"
}

->*

Dieses hier ist nur schwierig, da es nichts besonderes daran gibt. Die nicht überladene Version benötigt auf der linken Seite ein Objekt mit Zeiger auf den Klassentyp und auf der rechten Seite ein Objekt mit dem Zeiger auf den Elementtyp. Aber wenn Sie es überladen, können Sie beliebige Argumente nehmen und alles zurückgeben, was Sie wollen. Es muss nicht einmal ein nicht statisches Mitglied sein.

Mit anderen Worten, dieser ist nur ein normaler binärer Operator wie + , - und / . Siehe auch: Sind freie Betreiber -> * Überlasten böse?

.* und .

Diese können nicht überlastet werden. Es gibt bereits eine integrierte Bedeutung, wenn die linke Seite vom Klassentyp ist. Vielleicht würde es ein wenig Sinn machen, sie für einen Zeiger auf der linken Seite zu definieren, aber das Sprachdesignkomitee entschied, dass das verwirrender als nützlich wäre.

Überladen -> , ->* ,. , und .* kann nur Fälle ausfüllen, in denen ein Ausdruck undefiniert ist, er kann niemals die Bedeutung eines Ausdrucks ändern, der ohne Überladung gültig wäre.


Betreiber -> ist etwas Besonderes.

"Es hat zusätzliche, atypische Einschränkungen: Es muss ein Objekt (oder einen Verweis auf ein Objekt) zurückgeben, das auch einen Zeiger-Dereferenzierungsoperator hat, oder es muss einen Zeiger zurückgeben, mit dem ausgewählt werden kann, auf welchen Zeiger der Dereferenzierungsoperator zeigt. " Bruce Eckel: Denken CPP Vol-One: Operator->

Die zusätzliche Funktionalität ist der Bequemlichkeit halber vorgesehen, sodass Sie nicht anrufen müssen

a->->func();

Sie können einfach tun:

a->func();

Das unterscheidet Operator -> von den anderen Operatorüberladungen.


Sie können den Mitgliederzugriff nicht überlasten . (dh der zweite Teil von was -> tut). Sie können jedoch den unären Dereferenzierungsoperator * überladen (dh den ersten Teil von was -> tut).

Der C ++ -> Operator ist im Grunde die Vereinigung von zwei Schritten und das ist klar, wenn Sie denken, dass x->y äquivalent zu (*x).y . In C ++ können Sie anpassen, was mit dem Teil (*x) geschehen soll, wenn x eine Instanz Ihrer Klasse ist.

Die Semantik für -> Überladen ist etwas seltsam, weil C ++ Ihnen erlaubt, entweder einen regulären Zeiger zurückzugeben (damit das gespitzte Objekt gesucht wird) oder eine Instanz einer anderen Klasse zurückzugeben, wenn diese Klasse auch einen -> Operator liefert. Wenn in diesem zweiten Fall die Suche nach dem dereferenzierten Objekt von dieser neuen Instanz fortgesetzt wird.


Wenn Sie den Operator -> () überladen (hier werden keine Argumente übergeben), ruft der Compiler -> rekursiv auf, bis er einen tatsächlichen Zeiger auf einen Typ zurückgibt. Es verwendet dann das richtige Mitglied / die richtige Methode.

Dies ist beispielsweise nützlich, um eine intelligente Zeigerklasse zu erstellen, die den tatsächlichen Zeiger einkapselt. Der überladene Operator-> wird aufgerufen, tut was auch immer er tut (z. B. Sperren für Thread-Sicherheit), gibt den internen Zeiger zurück und dann ruft der Compiler -> für diesen internen Zeiger auf.

Wie für die Konstanz - es wurde in den Kommentaren und anderen Antworten beantwortet (Sie können und sollten beides bieten).





c++-faq