Inizializzazione, Assegnamento e Distruzione di Classi

Lezione 9
Costruttori e Distruttori
Inizializzazione, Assegnamento
e Distruzione di Classi
Lezione 9
ü In ogni programma C++ oggetti classe vengono
gestiti automaticamente dal compilatore
®
®
®
®
Inizializzati al momento della definizione
Assegnati ad altri oggetti della stessa classe
Convertiti in oggetti di altro tipo
Distrutti al termine del loro tempo di vita
ü Queste
operazioni
sono
eseguite
automaticamente dal compilatore invocando
metodi della classe
®
Il progettista della classe deve specificare come
queste operazioni devono essere eseguite
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Operazioni Automatiche
1
Laboratorio di Algoritmii e Strutture Dati
2001/02
1
Lezione 9
Costruttori e Distruttori
ü L’operazione di inizializzazione viene invocata subito
dopo che il compilatore ha allocato la memoria per un
oggetto della classe
®
Assegna valori iniziali a ciascuno dei membri dato dell’oggetto
ü Se i membri dato sono pubblici possono essere
inizializzati esplicitamente (come per uno struct)
class Dato {
public:
int ival;
char* ptr;
};
Dato d = {1204, “asd”};
Dato d2 = {“asd”, 1024);
// ERRORE
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Inizializzazione
2
ü Il meccanismo di inzializzazione più usato è il
costruttore
®
®
Metodo della classe invocato automaticamente dal
compilatore al momento dell’inizializzazione
Può inizializzare anche i membri dato privati
ü Il costruttore è un metodo della classe
® Ha lo stesso nome della classe
® Non ha tipo del risultato
® Può essere sovrapposto
® Non può essere definito sicuro
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Costruttore
3
Laboratorio di Algoritmii e Strutture Dati
2001/02
2
Lezione 9
Costruttori e Distruttori
class ContoCorrente {
public:
ContoCorrente( );
ContoCorrente( const char*, double, int);
private:
char* _nome;
unsigned int _numeroCc;
double _saldo;
};
ContoCorrente mioCC(“auletta”, 0, 123456);
/* alloca la memoria per mioCC e invoca la funzione
ContoCorrente::ContoCorrente per inizializzarla */
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Utilizzo di un Costruttore
4
ü Una classe può avere più costruttori per consentire
diversi tipi di utilizzo degli oggetti
®
®
Uno o più costruttori riservati agli utenti della classe
Un costruttore riservato agli amici della classe
class ContoCorrente {
friend class Banca;
public:
ContoCorrente( const char*, double = 0);
private:
ContoCorrente(const char*, int, double = 0);
char* _nome;
unsigned int _numeroCc;
double _saldo;
};
ContoCorrente mioCC(“auletta”);
Laboratorio di Algoritmii e Strutture Dati
2001/02
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Sovrapposizione di Costruttori
5
3
Lezione 9
Costruttori e Distruttori
ContoCorrente mioCC1(“Blundo”);
// Definisco un oggetto di tipo ContoCorrente in cui _nome è
// inizializzato con “Blundo” e _saldo con 0.0
// _numeroCc dipenderà dall’implementazione del costruttore
ContoCorrente suoCC(“Blundo”,1234.5);
// come prima ma _saldo è inizializzato a 1234.5
ContoCorrente mioCC2(“Blundo”,0,1234.5);
// Errore
// ContoCorrente(const char*, int, double = 0); è privato
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Esempi di uso di un costruttore
6
ü I costruttori vengono invocati ogni volta che
viene allocata della memoria ad un oggetto della
classe
®
®
®
®
Definizione di oggetti della classe
Passaggio per valore di oggetti ad una funzione
Creazione di un oggetto temporaneo
Allocazione dinamica di un oggetto
ü Nel caso dell’allocazione dinamica il costruttore
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Invocazione dei Costruttori
viene invocato solo se l’allocazione riesce
7
Laboratorio di Algoritmii e Strutture Dati
2001/02
4
Lezione 9
Costruttori e Distruttori
Invocazione dei Costruttori
da passare al costruttore
ContoCorrente mioCC(“auletta);
ContoCorrente mioCC = ContoCorrente(“auletta”);
ContoCorrente mioCC = “auletta”;
/* utilizzabile solo se il costruttore prende un solo
argomento */
ContoCorrente *ptrCC = new ContoCorrente(“auletta”);
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü Ci sono diverse forme per specificare gli argomenti
8
ü Il costruttore di default consente di inizializzare oggetti
della classe senza passare argomenti al costruttore
®
Il costruttore di default viene invocato quando non viene
specificate la lista degli argomenti per il costruttore
ContoCorrente mioCC;
ContoCorrente mioCC();
// Invoca il costruttore di default
// ERRORE
ü È possibile definire oggetti senza specificare argomenti
per il costruttore solo se non ci sono costruttori o c’è un
costruttore di default
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Costruttore di Default
9
Laboratorio di Algoritmii e Strutture Dati
2001/02
5
Lezione 9
Costruttori e Distruttori
ü Un array di oggetti di classe è definito normalmente
®
®
Nella lista di inizializzazione vengono specificati gli argomenti
per i costruttori
È possibile definire inizializzazioni parziali solo se la classe ha
un costruttore di default
ContoCorrente listaCC[10] =
{“baggio”, “del piero”, ContoCorrente(“totti”, 1000000)};
ü Se si alloca dinamicamente un array di oggetti di classe
non si possono passare argomenti ai costruttori
® La classe deve avere il costruttore di default oppure non deve
avere costruttori
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Array di Oggetti di Classe
10
ü È possibile definire vettori di oggetti di una classe
vector<ContoCorrente> archivio(5);
ü L’inizializzazione del vettore avviene secondo questi
passi
® Viene creata una variabile temporanea di tipo ContoCorrente
inizializzata per default
® Vengono inizializzati per copia tutti gli elementi del vettore
® Viene distrutta la variabile temporanea
ü L’inizializzazione di un vettore è meno efficiente di
quella di un array
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Vettori di Oggetti di Classe
® Conviene creare un vettore vuoto ed inserire gli elementi uno
per volta
Laboratorio di Algoritmii e Strutture Dati
2001/02
11
6
Lezione 9
Costruttori e Distruttori
ü Ogni costruttore che prende un solo argomento opera
come funzione di conversione
®
Utilizzato per creare oggetti temporanei della classe nella
valutazione di espressioni
ü Se si vuole impedire che un costruttore sia usato per
effettuare conversioni lo si può qualificare explicit
®
Un costruttore explicit viene usato per effettuare conversioni
solo se esplicitamente invocato dal programma
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Costruttori explicit
12
void f(const ContoCorrente& cc);
char* s=“Zoff”;
f(s);
// equivale a:
// ContoCorrente tmp(s);
// f(tmp);
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Esempio
13
Laboratorio di Algoritmii e Strutture Dati
2001/02
7
Lezione 9
Costruttori e Distruttori
ü È sempre possibile inizializzare un oggetto di una classe
con un altro oggetto della stessa classe
®
Inizializzazione membro a membro di default
®
Inizializza ogni membro dato con il corrispondente dato
dell’oggetto usato per l’inizializzazione
ü In molte situazioni la semantica dell’inizializzazione
membro a membro non corrisponde alle esigenze della
classe
®
Per la classe ContoCorrente l’oggetto inizializzato avrebbe lo
stesso numero di conto dell’oggetto usato per inizializzarlo
®
È possibile ridefinire la semantica definendo un costruttore per
copia
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Costruttori per Copia
14
Costruttori per Copia
riferimento costante
ContoCorrente::ContoCorrente(const ContoCorrente& cc) {
_nome = new char[strlen(cc._nome)+1];
strcpy(_nome, cc._nome);
_saldo = cc._saldo;
_numeroCc = _genera_numero_cc();
}
ContoCorrente mioCC(“auletta”, 1000);
ContoCorrente newCC(mioCC); //si usa il costruttore per copia
ContoCorrente newCC2 = mioCC; //si usa il costruttore per copia
ü Il costruttore per copia, se esiste, scavalca l’inizializzazione
membro a membro di default
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü Il costruttore per copia prende un solo argomento per
® Se esiste ma è privato il compilatore da errore
15
Laboratorio di Algoritmii e Strutture Dati
2001/02
8
Lezione 9
Costruttori e Distruttori
Distruttore di una Classe
ad un oggetto appena allocato le risorse che gli
occorrono
®
Memoria dinamica, file, periferiche
ü Prima di terminare il suo tempo di vita un oggetto
deve rilasciare le risorse che gli sono state assegnate
ü Il distruttore è un metodo speciale che provvede alla
deallocazione delle risorse
®
Viene automaticamente invocato prima che un oggetto venga
distrutto
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü Tra i compiti di un costruttore c’è quello di assegnare
16
Distruttore di una Classe
®
®
®
®
Il nome è uguale al nome della classe, preceduto da ~
Non prende argomenti
Non restituisce risultato
Non può essere sovrapposto
ContoCorrente::~ContoCorrente() {
delete [] _nome;
restituisci_numero_cc(_numeroCc);
}
ü Non tutte le classi necessitano di un distruttore
® Il distruttore non serve a deallocare la memoria assegnata ai
membri dato
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü Il distruttore è un metodo speciale
® Il distruttore dealloca oggetti referenziati da membri dato
17
Laboratorio di Algoritmii e Strutture Dati
2001/02
9
Lezione 9
Costruttori e Distruttori
ü Spesso si usa il distruttore per facilitare
il debugging del programma
®
Tiene traccia dello stato dei membri dato al
momento in cui l’oggetto cessa di esistere
®
Specifica quando gli oggetti escono dal
proprio scope
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Distruttori e Debugging
18
Inizializzazione di Membri Dato di
Classe
una classe X deve invocare il costruttore di X per
inizializzare il suo membro
®
Se la classe X non ha un costruttore di default si devono
necessariamente passare degli argomenti al costruttore della
classe
X
class ContoCorrente
{
public:
ContoCorrente( const string&, double, int);
ContoCorrente();
ContoCorrente(const ContoCorrente&);
private:
string _nome; /* per inizializzare _nome si deve invocare il
costruttore di string */
unsigned int _numeroCc;
double _saldo;
};
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü Se una classe ha un membro dato che è un oggetto di
19
Laboratorio di Algoritmii e Strutture Dati
2001/02
10
Lezione 9
Costruttori e Distruttori
Inizializzazione di Membri Dato di
Classe
(classe) presenta tre problemi
®
Come si invoca il costruttore di default di X
dall’interno del costruttore di default della classe
®
Come si invoca il costruttore per copia di X
dall’interno del costruttore per copia della classe
®
Come si passano gli argomenti al costruttore di un
membro dato
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü La presenza di un membro dato di tipo X
20
Lista di Inizializzazione
®
Utilizzata per inizializzare ogni membro della classe
ü La lista è tra la lista dei parametri della funzione ed il
corpo della funzione, ed è preceduta da :
ü La lista è formata da una sequenza di coppie separate da
,
®
Ogni coppia specifica il nome di un membro ed i valori con cui
deve essere inizializzato
ContoCorrente::ContoCorrente(const string& s, double valore) :
_nome(s), _saldo(valore) {
_numeroCc = _genera_numero_cc();
}
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü Ogni costruttore ha una lista di inizializzazione
21
Laboratorio di Algoritmii e Strutture Dati
2001/02
11
Lezione 9
Costruttori e Distruttori
ü Tutti i costruttori usano la lista di inizializzazione per
inizializzare i membri della classe
®
®
Tutte le operazioni fatte nel corpo del costruttore sono
assegnamenti
Se un membro non viene specificato nella lista viene inizializzato
tramite il costruttore di default
ü Tutti i membri della classe dovrebbero essere inizializzati
tramite la lista di inizializzazione
ü Devono essere necessariamente inizializzati tramite la
lista di inizializzazione
®
®
Oggetti i cui costruttori hanno bisogno di argomenti
Costanti
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Lista di Inizializzazione
22
ü Ogni membro deve comparire una sola volta
nella lista
ü L’ordine
delle
coppie
inizializzazione è ininfluente
®
®
nella
lista
di
I membri dato vengono inizializzati nell’ordine in cui
sono stati dichiarati nella definizione della classe
Ciò può essere fonte di errori!!
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Lista di Inizializzazione
23
Laboratorio di Algoritmii e Strutture Dati
2001/02
12
Lezione 9
Costruttori e Distruttori
class X {
int i;
int j;
public:
X(int val) : j(val), i(j) { }
// L’intenzione del programmatore è i = j = val
// vioene eseguito i = j; j = val;
// …
};
Se si deve inizializzare un membro di una classe con il
valore di un altro membro della stessa classe usare
l’assegnamento nel corpo del costruttore
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Cosa non va?
24
Assegnamento
ad un altro oggetto della stessa classe
L’operazione è gestita da un operatore di assegnamento
membro a membro di default
® Simile all’inizializzazione membro a membro di default
ContoCorrente& ContoCorrente::operator=(const ContoCorrente& cc) {
_nome = cc._nome;
_saldo = cc._saldo;
_numeroCc = cc._numeroCc;
return *this;
}
® Ha gli stessi problemi dell’inizializzazione membro a membro
di default
® Deve restituire un risultato di tipo ContoCorrente
®
Laboratorio di Algoritmi e Strutture Dati 2001
-02
ü È sempre possibile assegnare un oggetto di una classe
25
Laboratorio di Algoritmii e Strutture Dati
2001/02
13
Lezione 9
Costruttori e Distruttori
ü L’operatore
di assegnamento deve controllare gli
autoassegnamenti
®
®
Evita di perdere tempo a copiare un valore su se stesso
Garantisce che l’oggetto da cui stiamo copiando non sia stato
deallocato
ü L’operatore di assegnamento avrà sempre la seguente
forma:
NomeClasse& NomeClasse::operator=(const NomeClasse& nc) {
if( this != &nc ) {
// Effettua la copia
}
return *this;
}
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Operatore di Assegnamento
26
ContoCorrente& ContoCorrente::operator=(const ContoCorrente& cc) {
if( this != &cc ) {
_nome = cc._nome;
_saldo = cc._saldo;
_numeroCc = _genera_numero_cc();
}
return *this;
}
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Esempio di Operatore di Assegnamento
27
Laboratorio di Algoritmii e Strutture Dati
2001/02
14
Lezione 9
Costruttori e Distruttori
ü Costruttore di default
® NomeClasse();
ü Costruttore per copia
® NomeClasse(const NomeClasse&);
ü Costruttore per inizializzazione
® NomeClasse( • • • parametri di inizializzazione • • •);
Laboratorio di Algoritmi e Strutture Dati 2001
-02
Costruttori da inserire nelle classi
28
Laboratorio di Algoritmii e Strutture Dati
2001/02
15