2012-05-20 6 views
28

Ich verstehe die normale Überlastung des Bedieners. Der Compiler kann sie direkt in einen Methodenaufruf übersetzen. Ich bin mir nicht sehr klar über den -> Betreiber. Ich schrieb meinen ersten benutzerdefinierten Iterator und ich fühlte mich wie der - Operator. Ich warf einen Blick auf den Code stl Quelle und umgesetzt meine eigene wie es:Wie funktioniert das Überladen von Pfeil-> Operatoren intern in C++?

MyClass* MyClassIterator::operator->() const 
{ 
    //m_iterator is a map<int, MyClass>::iterator in my code. 
    return &(m_iterator->second); 
} 

Dann kann ich eine Instanz von MyClassIterator verwenden wie:

myClassIterator->APublicMethodInMyClass(). 

Sieht aus wie der Compiler zwei Schritte hier der Fall ist. 1. Rufen Sie die Methode ->() auf, um eine temporäre MyClass * -Variable zu erhalten. 2. Rufen Sie die APublicMethodInMyClass für die Variable temp auf und verwenden Sie ihren Operator ->.

Ist mein Verständnis korrekt?

Antwort

23
myClassIterator->APublicMethodInMyClass() 

ist nichts anderes als die folgende:

myClassIterator.operator->()->APublicMethodInMyClass() 

Der erste Aufruf der überladenen operator-> bekommt man einen Zeiger eines Typs, die eine leicht zugängliche (von Ihrem Anruf-site) Member-Funktion APublicMethodInMyClass() genannt hat. Die üblichen Funktionssuchregeln werden befolgt, um natürlich APublicMethodInMyClass() aufzulösen, abhängig davon, ob es sich um einen virtuellen Server handelt oder nicht.

Es gibt nicht unbedingt eine temporäre Variable; der Compiler kann den Zeiger, der von &(m_iterator->second) zurückgegeben wird, kopieren oder nicht kopieren. Aller Wahrscheinlichkeit nach wird dies weg optimiert werden. Es werden jedoch keine temporären Objekte vom Typ MyClass erstellt.

Die üblichen Einschränkungen gelten auch für m_iterator - stellen Sie sicher, dass Ihre Aufrufe nicht auf einen ungültigen Iterator zugreifen (d. H. Wenn Sie beispielsweise vector verwenden).

+2

Eigentlich ist es 'myClassIterator.operator ->() -> APublicMethodInMyClass()' –

+0

Danke für die Erklärung. Sollte der myClassIterator.operator ->(). APublicMethodInMyClass() myClassIterator.operator sein ->() -> APublicMethodInMyClass()? Der Rückgabetyp von ->() ist MyClass * – Ryan

+0

hab es. Danke Seth. – Ryan

66

Die operator-> hat eine spezielle Semantik in der Sprache, in der, wenn sie überladen ist, sie sich selbst auf das Ergebnis anwendet. Während der Rest der Operatoren nur einmal angewendet wird, wird vom Compiler so oft wie nötig angewendet, um zu einem unformatierten Zeiger zu gelangen, und noch einmal, um auf den von diesem Zeiger referenzierten Speicher zuzugreifen.

struct A { void foo(); }; 
struct B { A* operator->(); }; 
struct C { B operator->(); }; 
struct D { C operator->(); }; 
int main() { 
    D d; 
    d->foo(); 
} 

Im vorherigen Beispiel, in dem Ausdruck d->foo() die Compiler das Objekt nehmen d und gelten operator-> es, die ein Objekt vom Typ ergibt C, es wird dann den Bediener erneut eine Instanz von B zu bekommen, Wenden Sie sich erneut an und gehen Sie zu A*, wonach das Objekt deneferenziert wird und Sie zu den angegebenen Daten gelangen.

d->foo(); 
// expands to: 
// (*d.operator->().operator->().operator->()).foo(); 
// D   C   B   A* 
+1

Kannst du mich auf eine Referenz verweisen? Kann anscheinend keine finden. Niemand sonst erwähnt es. –

+7

@MilindR: 13.5.6/1 [...] * Ein Ausdruck x-> m wird interpretiert als '(x.operator ->()) -> m' für ein Klassenobjekt x vom Typ T if' T: : operator ->() 'existiert und wenn der Operator durch den Mechanismus der Überladungsauflösung als die beste Vergleichsfunktion ausgewählt wird * Wenn 'x-> operator ->()' einen Zeiger ergibt, wird dieser dereferenziert, wenn er ein Objekt von ergibt ein Typ, der 'operator ->()' überlädt, der Operator wird aufgerufen. –

+2

Dies sollte die richtige Antwort sein. –