81

Ho letto che un operatore sovraccarico dichiarato come funzione membro è asimmetrico perché può avere solo un parametro e l'altro parametro passato automaticamente è il puntatore "this". Quindi non esiste uno standard per confrontarli. D'altra parte, l'operatore sovraccaricato dichiarato come amico è simmetrico perché passiamo due argomenti dello stesso tipo e quindi, possono essere confrontati. La mia domanda è che quando posso ancora confrontare il lvalue di un puntatore a un riferimento, perché gli amici sono preferiti? (utilizzando una versione asimmetrica fornisce gli stessi risultati di simmetrica) Perché gli algoritmi STL utilizzano solo versioni simmetriche?Sovraccarico dell'operatore: funzione membro vs. funzione non membro?

+9

La tua domanda è in realtà solo circa operatori binari. Non tutti gli operatori sovraccaricati sono limitati a un singolo parametro. L'operatore() può prendere qualsiasi numero di parametri. Gli operatori unari, d'altra parte, non possono avere alcun parametro. –

+1

http://stackoverflow.com/a/4421729/103167 –

+2

Questo è uno dei molti argomenti trattati nelle [Domande frequenti su C++: overloading dell'operatore] (http://stackoverflow.com/questions/4421706/operator-overloading) –

risposta

101

Se si definisce la funzione overload dell'operatore come funzione membro, il compilatore traduce espressioni come s1 + s2 in s1.operator+(s2). Ciò significa che la funzione membro sovraccaricato dell'operatore viene richiamata sul primo operando. Ecco come funzionano le funzioni dei membri!

Ma cosa succede se il primo operando non è una classe? C'è un grosso problema se vogliamo sovraccaricare un operatore in cui il primo operando non è un tipo di classe, per esempio double. Quindi non è possibile scrivere in questo modo 10.0 + s2. Tuttavia, è possibile scrivere la funzione membro sovraccaricato dell'operatore per espressioni come s1 + 10.0.

Per risolvere questo problema ordinare, definiamo funzione sovraccaricata operatore friend IF è necessario accedere private membri. Make it friend SOLO quando è necessario accedere ai membri privati. Altrimenti, semplicemente rendi la funzione non-utente non membro a migliorare l'incapsulamento!

class Sample 
{ 
public: 
    Sample operator + (const Sample& op2); //works with s1 + s2 
    Sample operator + (double op2); //works with s1 + 10.0 

    //Make it `friend` only when it needs to access private members. 
    //Otherwise simply make it **non-friend non-member** function. 
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2 
} 

Leggere questi:
A slight problem of ordering in operands
How Non-Member Functions Improve Encapsulation

+2

"Falla" amico "solo quando ha bisogno di accedere ai membri privati..e quando non hai/sono stanco di scrivere accessor, giusto? – badmaash

+4

@Abhi: Scegli la tua scelta: Incapsulamento migliorato contro la scrittura pigra! – Nawaz

+0

Sono noti casi in cui non si poteva semplicemente evitare la parola chiave 'friend' avendo l'operatore globale' '+()' semplicemente 'return op2.operator + (op1);'? In entrambi i casi, + per default non modificava il campione di input, e invece restituisci una nuova istanza rvalue di 'Sample', giusto? – matthias

14

Ma non è necessariamente una distinzione tra friend sovraccarichi operatore e overload dell'operatore funzione membro com'è fra globale overload dell'operatore e sovraccarichi operatore funzioni membro.

Uno dei motivi per preferire un sovraccarico di operatore globale è se si desidera consentire le espressioni in cui viene visualizzato sul lato destro di un operatore binario del tipo di classe. Ad esempio:

Foo f = 100; 
int x = 10; 
cout << x + f; 

Questo funziona solo se v'è un sovraccarico operatore globale per

Foo operatore + (int x, const Foo & f);

Si noti che il sovraccarico dell'operatore globale non deve necessariamente essere una funzione friend. Questo è necessario solo se ha bisogno di accedere ai membri privati ​​di Foo, ma non è sempre il caso.

Indipendentemente da ciò, se Foo solo avuto un sovraccarico di operatore di funzione membro, come:

class Foo 
{ 
    ... 
    Foo operator + (int x); 
    ... 
}; 

... allora ci sarebbe solo in grado di avere le espressioni in cui viene visualizzato un esempio Foo sul sinistra dei plus operatore.

+1

+ 1 per fare la distinzione tra funzioni membro e funzioni non membri piuttosto che funzioni membro e amico. Credo che oggi potremmo dire "portata globale o spazio dei nomi". –

Problemi correlati