2012-05-20 15 views
28

Capisco il normale sovraccarico dell'operatore. Il compilatore può tradurli direttamente in metodo call. Non sono molto chiaro sull'operatore ->. Stavo scrivendo il mio primo iteratore personalizzato e sentivo il bisogno di -> operatore. Ho preso uno sguardo al codice sorgente AWL e realizzato il mio simile al primo:In che modo l'utilizzo di arrow-> overloading internamente funziona in C++?

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

allora posso utilizzare un'istanza di MyClassIterator come:

myClassIterator->APublicMethodInMyClass(). 

Sembra che il compilatore fa due passi qui. 1. Chiama il metodo ->() per ottenere una variabile MyClass * temporanea. 2. Chiama APublicMethodInMyClass sulla variabile temp usa il suo operatore ->.

La mia comprensione è corretta?

risposta

23
myClassIterator->APublicMethodInMyClass() 

non è altro che il seguente:

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

La prima chiamata al sovraccarico operator-> si ottiene un puntatore di un certo tipo che ha un accesso funzione membro (dal call-site) chiamato APublicMethodInMyClass(). Le solite regole di ricerca delle funzioni sono seguite per risolvere APublicMethodInMyClass(), ovviamente, a seconda che si tratti di un sistema virtuale o meno.

Non esiste necessariamente una variabile temporanea; il compilatore può o non può copiare il puntatore restituito da &(m_iterator->second). Con ogni probabilità, questo sarà ottimizzato. Tuttavia, non verranno creati oggetti temporanei di tipo MyClass.

I caveat usuali si applicano anche a m_iterator - assicurarsi che le chiamate non accedano a un iteratore invalidato (ad esempio se si utilizza vector ad esempio).

+2

realtà è 'myClassIterator.operator ->() -> APublicMethodInMyClass()' –

+0

Grazie per la spiegazione. Il myClassIterator.operator ->(). APublicMethodInMyClass() dovrebbe essere myClassIterator.operator ->() -> APublicMethodInMyClass()? Il tipo di ritorno di ->() è MyClass * – Ryan

+0

ottenuto. Grazie Seth. – Ryan

66

Il operator-> ha una semantica speciale nella lingua in quanto, sovraccaricato, si riapplica al risultato. Mentre il resto degli operatori viene applicato una sola volta, il compilatore applica il numero operator-> tante volte quanto necessario per raggiungere un puntatore non elaborato e ancora una volta per accedere alla memoria indicata da quel puntatore.

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

Nell'esempio precedente, nell'espressione d->foo() il compilatore prendere l'oggetto d e applicare operator-> ad esso, che produce un oggetto di tipo C, sarà poi riapplicare l'operatore per ottenere un'istanza di B, riapplicare e arrivare a A*, dopo di che sarà dereferenziare l'oggetto e ottenere i dati appuntiti.

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

Puoi indicarmi un riferimento su questo? Non riesco a trovare nessuno. Nessun altro lo menziona. –

+7

@MilindR: 13.5.6/1 [...] * Un'espressione x-> m viene interpretata come '(x.operator ->()) -> m' per un oggetto di classe x di tipo T se' T: : operator ->() 'esiste e se l'operatore è selezionato come la funzione di corrispondenza migliore dal meccanismo di risoluzione del sovraccarico * Se' x-> operator ->() 'produce un puntatore, esso viene dereferenziato, se restituisce un oggetto di un tipo che sovraccarica l'operatore '->()' che viene richiamato dall'operatore. –

+2

Questa dovrebbe essere la risposta corretta. –

Problemi correlati