Newsgroup: it.comp.lang.c++
Titolo: ridefinire operatore

Salve a tutti,
la domanda magari č molto banale, ma come potrei fare per ridefinire
l'operatore '+' in una classe?
Supponiamo io voglia creare una classe "intero" che definisce numeri tipo
int. Vorrei che l'operatore + applicato a due oggetti di questa classe
facesse una concatenazione, o una sottrazione, insomma chiamasse un metodo
definito da me.
E' una stupidaggine?
Grazie a tutti

 E' una stupidaggine?
no, il c++ permette di ridefinire gli operatori (non tutti comunque) 
proprio per questo motivo (vedi la keyword operator sul tuo manuale del 
linguaggio per maggiori info).
-- 
si prepara direttamente nel bicchiere basso detto "tumbler basso". Tre o 
quattro cubetti di ghiaccio, aggiungere il gin, il martini rosso, il 
bitter campari e mescolare. Guarnire con una fetta d'arancia.

 definito da me.
Ecco un semplice esempio che somma due "Interi" ovvero oggetti di tipo
Interi (non int inteso come tipo predefinito):
#include <iostream>
class Intero {
 int i;
 public :
 Intero(int y = 0) : i(y) {};
 int operator +(Intero& I) {
  return i + I.i;
 };
};
int main() {
 Intero x(4);
 Intero y(5);
 std::cout << x + y << std::endl;
 return 0;
}
Nota che quel + e' quello definito nella classe infatti se fai x + 1 ad es.
non funziona perche' non e' definito un operatore + tra un Intero e un int.
Ciao

Un paio osservazioni:
1) questa sarebbe una dichiarazione piu' appropriata:
  const Intero Intero::operator +(const Intero&I) const {
    return Intero(i + I.i);
  }
in quanto ti aspetteresti che l'operatore + ritorni lo stesso tipo
dei suoi argomenti.
Inoltre i due argomenti dovrebbero essere dichiarati const.
In questo modo, infatti, puoi fare:
  Intero x(3);
  Intero y = x + 1;
(questo perche' il costruttore non e' dichiarato 'explicit', e quindi,
all'occorrenza viene costruito un temporaneo const Intero(1) e passato
all'operatore +).
Il tipo di ritorno e' a sua volta const per impedire cose del tipo
(x+1)=5;
2) sarebbe ancora piu' appropriato, pero' dichiarare l'operatore + come
funzione esterna alla classe:
// N.B. se non abbiamo metodi pubblici per accedere al valore di a e b
// dovremo dichiarare l'operatore + come friend di Intero.
//
const Intero operator+(const Intero& a, const Intero& b) {
  return Intero( a.i + b.i );
}
Cosi', in questo caso puoi anche avere:
  Intero x(3);
  Intero y = 1 + x;
In generale, comunque, e' buona pratica avere costruttori explicit ed
evitare conversioni automatiche "involontarie".
Saluti,
Fabio

 Un paio osservazioni:
Si, diciamo che l'ho scritto un po cosi al volo :P
Ciao

 evitare conversioni automatiche "involontarie".
Ma in questo caso:
Intero x = 1;
rispecchia un'uso corretto di int quindi perche' vietarlo?
Ciao

 ha scritto nel messaggio
news:4235f...@x-privat.org...

Dipende tutto dall'interpretazione del tipo "Intero". Se qualcuno definisce
una classe di questo tipo, che al suo interno contiene un int, lo fa perchè
probabilmente vuole impedire che su oggetti di questa classe vengano
eseguite operazioni che sono invece possibili su un normale intero. In tal
caso potrebbe aver senso mantenere un maggiore controllo, impedendo di
passare, per errore, un semplice int a una funzione che vuole un Intero (e
quindi il costruttore dovrebbe essere explicit), e potrebbe aver senso
impedire la stampa di un Intero. E'chiaro che il caso in esame è un esempio
banale, però con una classe più significativa (per esempio un Intero con un
range di valori limitati) le considerazioni che ha fatto Fabio sono da
tenere in conto.
Ciao!
Walter

 le considerazioni che ha fatto Fabio sono da tenere in conto.
Ma certo, soltanto va analizzato il caso specifico di volta in volta :)
Ciao

evitare conversioni automatiche "involontarie".
Nel caso della classe in questione l'explicit non e' strettamente
necessario, ma in casi piu' comuni
(con classi cioe' non proprio banali) i costruttori non-explicit
possono causare comportamenti inattesi.
Per es. in una classe del genere:
// un array di interi
class IntArray {
  public:
    // crea un array con "size" elementi, inizializzati a 0
    Array(int size);
   // concatena due array
   Array operator+(const Array& a) const;
 ...
  // vari metodi per accedere agli elementi omessi
};
IntArray x(5);
IntArray y(3);
// assegnamo i valori ai vari elementi
...
IntArray z = x + y; // ok: z avra' 8 elementi
IntArray w = x + 2; // compila ma aggiunge due elementi nulli
                    // e non un '2' come ci si potrebbe aspettare
Ma in generale, e' meglio evitare l'overload di operatori quando il
loro comportamento non e' assolutamente ovvio ed intuitivo. (Insomma,
usare con moderazione ;-)
Saluti,
Fabio