La classe numero complesso
In questo capitolo amplieremo le nostre conoscenze riguardo all'uso delle classi e parleremo dell'overloading.
L'overloading consiste nel sovraccaricare un operatore o una funzione per far si che essa funzioni con variabili aventi tipi diversi. Ad esempio nel seguito del capitolo vedremo come sovraccaricare l'operatore + per far si che esso sommi due numeri complessi.
Il modo in cui abbiamo scritto il codice precedente non permette un facile ri-uso... scriviamo quindi la nostra classe complessa in modo tale che essa sia riusabile in qualsiasi momento. Per fare ciò basta dividere il codice nelle seguenti parti:
- Un file di tipo header dove scrivere la dichiarazione di classe (complex.h)
- Un file di tipo cpp dove deve essere inserito il precedente file header e in cui vanno definite le funzioni il cui prototipo si trova nella definizione di classe.
- Un terzo file, che includa il file header di classe, dove scriveremo il nostro main.
e rispondendo di "sì" alla richiesta di se vogliamo aggiungere tale file al progetto corrente.
A questo punto salviamo con nome i tre file che compaiono cliccando su
e diamo a tali file i nomi:
- complex.h
- complex.cpp
- main.cpp
Dovreste aver ottenuto la seguente schermata:

#include <iostream>
using namespace std;
class complex{
//overloading di estrazione dello streaming
friend ostream &operator<<( ostream & , const complex &);
//overloading di immissione dello streaming
friend istream &operator>>( istream &, complex & );
public:
//costruttore
complex(double = 0.0 , double = 0.0 );
//overloading vari
complex operator+(const complex & )const;
complex operator-(const complex & )const;
complex &operator=(const complex & );
complex operator*(const complex &)const;
bool operator==(const complex &)const;
bool operator!=(const complex &)const;
private:
//come nell'esempio precedente
double parteReale;
double parteImmaginaria;
};
In questo codice vediamo la presenza di una nuova keyword (friend) la quale sta a significare che a quei dati possono accedere solo le funzioni della classe; in particolare noi accederemo agli operatori << e >> rispettivamente delle classi ostream (che sta per output stream) e istream (che sta per input stream).
I parametri specificati tra parentesi rappresentano un oggetto ostream/istream passato per riferimento (&) e un oggetto complex sempre passato per riferimento, con la clausola const nel caso dell'ostream in quanto quell'oggetto non deve essere modificato.
Segue la distinzione in parte pubblica e privata come visto in precedenza.
complex(double = 0.0 , double = 0.0 )
sta a significare che il costruttore per default inizializza a zero i due parametri anche se non lo specifichiamo.
Dopo c'è l'overloading dei vari operatori che intendiamo usare.
Nota: qualsiasi classe avete intenzione di sviluppare sappiate che il prototipo dei vari operatori deve essere sempre questo, quindi tenete tali prototipi a modello e cambiate solo ciò che è necessario (ovvero dove compare complex dovrete scrivere il nome della vostra classe).
La parte privata è la stessa dell'esempio precedente.
Vediamo ora il codice da scrivere in complex.cpp:
#include "complex.h"
#include <iostream>
using namespace std;
//costruttore
complex::complex( double r, double i)
{
parteReale = r;
parteImmaginaria = i;
}
//overloading vari
ostream &operator<<(ostream &output , const complex &p)
{
if (p.parteImmaginaria >= 0)
output << '(' << p.parteReale << "+j"
<< p.parteImmaginaria << ')' << endl;
else
output << '(' << p.parteReale << "-j"
<< p.parteImmaginaria*-1 << ')' << endl;
return output;
}
istream &operator>>( istream &input, complex &a )
{
input >> a.parteReale >> a.parteImmaginaria;
return input;
}
//overloading somma
complex complex::operator+(const complex &addendo2)const
{
return complex ( parteReale + addendo2.parteReale ,
parteImmaginaria + addendo2.parteImmaginaria);
}
//overloading differenza
complex complex::operator-(const complex &addendo2)const
{
return complex ( parteReale - addendo2.parteReale ,
parteImmaginaria - addendo2.parteImmaginaria);
}
//operatore di assegnamento
complex& complex::operator=(const complex &rValue )
{
parteReale = rValue.parteReale;
parteImmaginaria = rValue.parteImmaginaria;
return *this;
}
//operatore di moltiplicazione
complex complex::operator*(const complex &fattore2)const
{
return complex(parteReale * fattore2.parteReale -
parteImmaginaria * fattore2.parteImmaginaria,
parteImmaginaria * fattore2.parteReale +
parteReale * fattore2.parteImmaginaria);
}
//operatore di uguaglianza
bool complex::operator==(const complex &pippo)const
{
if (parteReale==pippo.parteReale &&
parteImmaginaria==pippo.parteImmaginaria)
return true;
else
return false;
}
//operatore diverso da
bool complex::operator!=(const complex &pluto)const
{
if (parteReale!=pluto.parteReale &&
parteImmaginaria!=pluto.parteImmaginaria)
return true;
else
return false;
}
In tale codice è contenuta la dichiarazione delle funzioni membro e la ridefinizione degli operatori.
Esamineremo solo alcuni di questi operatori in quanto la comprensione di tale codice dovrebbe ormai essere semplice:
Notiamo che vi è l'inclusione del file dove è definita la dichiarazione della classe complex ovvero l'istruzione #include "complex.h".
ostream &operator<<(ostream &output , const complex &p)
significa che stiamo per ridefinire l'operatore << il quale restituisce un oggetto di tipo ostream e prende in ingresso una variabile di tipo ostream chiamata output e un const complex, constante poichè non deve essere modificato. All'interno delle parentesi graffe vi è scritta la stessa funzione che avevamo chiamato nell'esempio precedente stampaComplesso, il vantaggio è che ora possiamo permetterci di incanalare nello streaming d'uscita un numero complesso utilizzando l'operatore <<.
complex complex::operator+(const complex &addendo2)const
tale ridefinizione agisce sull'operatore di somma il quale deve restituire un ogetto di tipo complex prendendo in ingresso il secondo addendo che deve essere sempre un complex, a questo punto la funzione non fa altro che restituire la somma della parte reale con la parte reale che gli passiamo in input e lo stesso per la parte immaginaria. Tali somme vengono date come input al costruttore della classe complex.
complex& complex::operator=(const complex &rValue )
indica che stiamo ridefinendo l'operatore di assegnazione il quale restituirà un complex, prendendo in input un altro complex dichiarato const e chiamato rValue (valore di destra). Il corpo della funzione non fa altro che copiare i valori di rValue in quelli dell'oggetto associato in quel momento all'operatore. Inoltre vi è la riga return *this; la quale sta a significare che si restituisce il valore dell'oggetto puntato. Facciamo un esempio:
-
complex x(10,-3); //corrisponde a 10-j3
complex y; //crea un nuovo oggetto complex
y=x; //ad y viene associato il valore 10-j3
In ultimo vi è il codice da inserire nel main.cpp:
#include <iostream>
#include "complex.h"
using namespace std;
int main()
{
//costruisce a con valori di default
complex a;
cout << "Valore di deafult del numero complesso a: "<<a;
cout<< "\nImmetti i nuovi valori di a" << endl;
//modifica a
cin >> a;
cout << a;
//cotruisce b con i valori di a
complex b(a);
cout << "Istanziamo b mediante il costruttore con i valori di a"
<< endl;
cout << "b vale: " << b;
//inizializza c con i valori 3 e -5
complex c(3,-5);
cout << "\nViene istanziato c con i seg. valori" << c;
cout << "\nLa somma di c e b e': " << c+b;
cout << "\nVerifica dell'operatore di assegnamento con c=b" ;
c=b;
cout << "\nOra c dovrebbe vale quanto b "<< c;
cout << "\na: " << a;
cout << "\nc: "<<c;
cout << "\nc*a: "<< c*a;
if (a==b)
cout << "a e' uguale a b" << endl;
else
cout << "a e' diverso da b" << endl;
//instanzia un oggetto con valori 89 e 87
complex d(89,87) ;
if (c!=d)
cout << "c e d sono diversi" << endl;
system ("PAUSE");
return 0;
}
Unica nota importante da fare al main è l'inclusione del file #include "complex.h" grazie al quale possiamo utilizzare la classe complex con tutte le sue funzioni. Il resto sono semplici operazioni di input/output eseguite grazie all'overloading degli operatori di streaming.
Arrivati a questo punto siamo in grado di gestire una classe.







