2012-05-05 17 views
7

Si dice che l'operatore di freccia sia applicato in modo ricorsivo. Ma quando provo ad eseguire il codice seguente, esso stampa senza senso quando si suppone che la stampa 4.applicazione ricorsiva di operatore->

class dummy 
{ 
public: 
    int *p; 

    int operator->() 
    { 
     return 4; 
    } 
}; 

class screen 
{ 
public: 
    dummy *p; 

    screen(dummy *pp): p(pp){} 
    dummy* operator->() 
    { 
     return p; 
    } 
}; 

int main() 
{ 
    dummy *d = new dummy; 
    screen s(d); 
    cout<<s->p; 
    delete d; 
} 
+6

Dove si dice che è "applicato in modo ricorsivo"? –

+0

No, non sono d'accordo sul fatto che l'esempio funzioni come previsto, l'operatore -> è semplicemente una chiamata di funzione, in sostanza, perché dovrebbe eseguire il drill down? Se lo fa, come controlleresti a quale livello smettere di dereferenziare e renderebbe ancora più complicato l'ereditarietà e il polimorfismo di quello che è già – EdChum

+2

Primer C++, quarta edizione di Stanley B. Lippman, sezione 14.6 ultimo paragrafo. – user1232138

risposta

10

Che Stanley intende per “ricorsiva” è solo che l'operatore è applicato a ogni oggetto restituito fino la il tipo restituito è un puntatore.

Che succede qui al primo tentativo: screen::operator -> restituisce un puntatore. Quindi questa è l'ultima chiamata a un operator -> che il compilatore tenta. Risolve quindi il sorso destro dell'operatore (p) cercando un membro nel tipo di punta restituito (dummy) con quel nome.

In sostanza, quando il compilatore trova la sintassi aᵢ->b in codice, vale essenzialmente il seguente algoritmo:

  1. È aᵢ di tipo puntatore? In tal caso, risolvere il membro b di *aᵢ e chiamare (*aᵢ).b.
  2. Else, cercare di risolvere aᵢ::operator ->
    1. In caso di successo, insieme aᵢ₊₁ = aᵢ::operator ->(). Goto 1.
    2. In caso di errore, emettere un errore di compilazione.

Sono difficoltà a venire con una breve, significativo esempio dove un catena di operator -> invocazioni rende ancora senso. Probabilmente l'unico vero uso è quando scrivi una classe puntatore intelligente.

Tuttavia, il seguente esempio di giocattolo almeno compila e produce un numero. Ma non consiglierei davvero di scrivere questo codice. Rompe l'incapsulamento e fa piangere i gattini.

#include <iostream> 

struct size { 
    int width; 
    int height; 
    size() : width(640), height(480) { } 
}; 

struct metrics { 
    size s; 
    size const* operator ->() const { 
     return &s; 
    } 
}; 

struct screen { 
    metrics m; 
    metrics operator ->() const { 
     return m; 
    } 
}; 

int main() { 
    screen s; 
    std::cout << s->width << "\n"; 
} 
+0

forse il mio concetto sarebbe più chiaro se mi si potrebbe dire come posso ottenere da 4 a essere stampato in questo esempio .. – user1232138

+0

@ user1232138 Non è possibile. L'ultima chiamata nella catena di 'operator ->' ** deve ** restituire un puntatore. –

+0

@ user1232138 Tuttavia, vedere il mio aggiornamento per un esempio funzionante. Nota che ciò che ho detto prima vale ancora. È necessario restituire un puntatore - quindi se si desidera recuperare un valore intero, ha bisogno di essere conservato nell'espressione lato destro dell'operatore (in questo caso, 'formato :: width'). –

0

L'operazione è volta screen::operator->() restituisce un puntatore (dummy*) la ricorsione si ferma perché built-in (default) -> in utilizzati in quel puntatore. Se si desidera che la ricorsione è necessario restituire dummy o dummy& da screen::operator->()

1

C++ Primer (5a edizione) formula come segue a pagina 570:

L'operatore freccia mai non perde il suo significato fondamentale di accesso utente. Quando sovraccarichiamo la freccia, cambiamo l'oggetto da cui la freccia recupera il membro specificato. Non possiamo cambiare il fatto che la freccia recupera un membro.