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