2011-02-04 24 views
17

Qui è il mio esempio di codice:overloading degli operatori ->

class X 
{ 
public: 
     void f() {} 
}; 

class Y : public X 
{ 
public: 
     X& operator->() { return *this; } 
     void f() {} 
}; 

int main() 
{ 
     Y t; 
     t.operator->().f(); // OK 
     t->f(); // error C2819: type 'X' does not have an overloaded member 'operator ->' 
       // error C2232: '->Y::f' : left operand has 'class' type, use '.' 
} 

Perché il compilatore sta cercando di "spostare la responsabilità" per la seconda del gestore> da Y a X? Quando implemento X :: op-> quindi non posso restituire X lì - l'errore di compilazione dice "ricorsione infinita" mentre restituisco un po di Z da X :: op-> di nuovo dice che Z non ha operatore->, andando così in alto e più in alto nella gerarchia.

Qualcuno può spiegare questo comportamento interessante? :)

risposta

18

Il problema è che operator -> deve restituire un puntatore, non un di riferimento. L'idea è che operator -> restituisca un puntatore all'oggetto reale a cui dovrebbe essere applicato il puntatore. Ad esempio, per una classe con un sovraccarico operator ->, il codice

myClass->myValue; 

traduce in

(myClass.operator->())->myValue; 

Il problema con il vostro codice è che operator -> restituisce un riferimento, in modo da scrivere

myClass.operator->().f(); 

è perfettamente legale perché stai invocando esplicitamente l'operatore, ma scrivendo

myClass->f(); 

è illegale, perché il compilatore sta cercando di espandersi a

myClass.operator->()->f(); 

e il tipo di ritorno di operator-> non è un puntatore.

Per risolvere questo problema, modificare il codice in modo da restituire un puntatore in operator ->. Se si desidera sovraccaricare un operatore per restituire un riferimento, sovraccaricare operator *; le dereferenze puntate dovrebbero in effetti produrre riferimenti.

+9

io non direi che è supponiamo di restituire un puntatore, basta che qualunque cosa ritorna deve supportare 'del gestore>'. – GManNickG

+1

@ GMan- Buon punto. Stavo andando per semplicità qui, ma tu hai ragione. Ci sono alcuni trucchi davvero divertenti che puoi utilizzare con puntatori intelligenti basati su questa tecnica. – templatetypedef

+0

@GMan: Poiché tali tipi sono chiamati collettivamente * puntatori intelligenti *, non penso che templatetypedef abbia torto ad usare il termine * puntatore *, lo sta semplicemente usando in senso generale. –

2

La sintassi è sbagliato, dovrebbe essere:

T-> T2

T2* T::operator ->();​ 

Guarda l'articolo di Wikipedia: Operators in C and C++

Se si vuole sovraccaricare, è necessario utilizzare la sintassi corretta per l'operatore sovraccarico

19

Perché è così anche Aded -> funziona in C++.

Quando si utilizza il sovraccarico ->, l'espressione a->b viene convertita in a.operator->()->b. Ciò significa che l'operatore sovraccarico -> deve restituire qualcosa che supporterà automaticamente un'altra applicazione dell'operatore ->. Per questo motivo una singola chiamata di sovraccarico -> potrebbe trasformarsi in una lunga catena di invocazioni di sovraccarico -> s fino a quando non raggiunge un'applicazione di -> integrata, che termina la catena.

Nel tuo caso è necessario restituire dal sovraccarico ->, non X&.

1

probabilmente si vuole:

class Y : public X 
{ 
public: 
     X* operator->() { return this; } 
     void f() {} 
}; 
Problemi correlati