2012-04-28 5 views
5

Diciamo che abbiamo questa classe A:Come si utilizza una catena di overload dell'operatore senza modificare gli operandi?

class A 
{ 
public: 
    int a; 

    A(int b) 
    { 
     a = b; 
    } 
}; 

Vorrei creare un sovraccarico di + tale che ho potuto usare in questo modo

A a(1),b(2),c(3),&d; 
d = a + b + c; 

senza modificare il contenuto di ciascun oggetto. La prossima cosa più logica sarebbe l'assegnazione di una nuova porzione di memoria ogni momento come questo:

A &operator+ (const A &b) 
{ 
    A *c = new A(a+b.a); 
    return *c; 
} 

Ma questo creerebbe un nuovo problema: risultati intermedi sono persi, causando perdite di memoria. Avrei potuto facilmente risolvere questo problema creando una funzione statica che prende tre riferimenti A object e memorizza la somma dei primi due nel terzo, ma sono disposto a scommettere che ci deve essere un modo per fare + sovraccaricare il modo che voglio

Quindi la domanda è: esiste un modo per utilizzare una catena di overload dell'operatore che non modifichi gli operandi senza causare perdite di memoria?

risposta

9

Puoi semplicemente utilizzare il passaggio per valore e fare questo:

A operator+ (A other) //pass by value 
{ 
    other.a += a; 
    return other; 
} 

Oppure, dal momento che il membro a è accessibile al pubblico, è possibile (anzi dovrebbe) fare operator+ una funzione non membro come :

A operator+(A left, A const &right) 
{ 
    left.a += right.a; 
    return left; 
} 

si noti che il primo argomento è accettato per valore, e in secondo luogo per riferimento. In questo modo, non è necessario dichiarare una variabile locale nella funzione. Puoi usare il primo parametro; dopotutto è locale alla funzione, puoi fare tutto ciò che vuoi fare con esso: in questo caso, aggiungiamo semplicemente right.a e lo restituiamo.


Una migliore progettazione di classe sarebbe questo: (leggere i commenti)

class A 
{ 
    int a; //make it private 
public:  
    A(int b) : a(b) //use member initialization list 
    { 
    } 
    A& operator+=(A const & other) //add `+=` overload, as member of the class 
    { 
     a += other.a; 
     return *this; 
    } 
}; 

//and make `+` non-member and non-friend 
A operator+(A left, A const & right) 
{ 
    left += right; //compute this in terms of `+=` which is a member function 
    return left; 
} 
+1

+1 per evitare la copia manuale. – Sven

+0

scusa ma la tua risposta sembra aver ignorato il fatto che mi stavo chiedendo in particolare un modo per non modificare nessuno degli oggetti operando –

+0

@ user803253: Non modifico gli * operandi *; gli operandi vengono passati come valore, il che significa che le modifiche apportate alla funzione sono * copie * degli operandi. Ad ogni modo, ho pubblicato un design migliore che dovresti adottare. – Nawaz

4

Non è necessario utilizzare i puntatori all'interno di operator+. È possibile assegnare l'oggetto intermedio nello stack e poi tornare:

A operator+ (const A &b) 
{ 
    A c(a+b.a); 
    return c; 
} 

O semplicemente:

A operator+ (const A &b) 
{ 
    return A(a+b.a); 
} 

O ancora più semplice:

A operator+ (const A &b) 
{ 
    return a+b.a; 
} 

Dal momento che questo richiama implicitamente A::A(int).

Si noti che ho rimosso il riferimento dal tipo di ritorno. Non è possibile restituire un riferimento non const a un locale.

allora si potrebbe utilizzare in questo modo:

A a(1),b(2),c(3),d; 
d = a + b + c; 

noti che d non è più un punto di riferimento.

+0

Alert: State ritornando riferimenti a provvisori. Non è una buona idea! –

+0

funziona alla grande! Grazie. Sapevo che doveva essere fatto qualcosa di semplice. –

+0

Appena ho postato la mia risposta, ho notato che OP stava restituendo riferimenti, ma ho risolto subito la mia risposta. – mfontanini