Derivazione di Classi Derivazione di Classi l’operazione di ereditarietà della programmazione ad oggetti ü La classe derivata può utilizzare tutti i dati ed i metodi non privati della classe base come propri elementi Lezione 14 ® non c’è bisogno di riscrivere i metodi ereditati dalla classe base, a meno che non debbano essere modificati ü Il livello di accesso di un membro della classe può essere privato, pubblico e protetto ® i membri protetti non sono visibili dall’esterno della classe ma sono ereditabili Laboratorio di Algoritmi e Strutture Dati 2000-01 ü Il meccanismo della derivazione di classi implementa Derivazione di Classi Costruzione di Nuovi Tipi per Composizione ü La definizione di una classe derivata richiede la ü Avremmo potuto anche definire la classe Window class Window : public Video { protected: short origine_x, origine_y; public: void trasla(int, int); // nuovo metodo char dammi(int, int); // ridefinizione … }; come contenente un oggetto Video class Window2 { Video V; short origine_x, origine_y; public: … }; Window2 W; // la larghezza della finestra è contenutra in W.V.larghezza 2 3 Derivazione Singola e Multipla ü Dichiarazione del template di classe list di LEDA ü Ogni classe può specificare una o più classi base class dlink; class dlist { dlink* h; dlink* t; int count; …. }; template <class T> class list : public dlist { … }; Laboratorio di Algoritmi e Strutture Dati 2000-01 Esempio 4 Laboratorio di Algoritmi e Strutture Dati 2001-02 da cui ereditare dati e metodi ü L’insieme delle classi e le relazioni di derivazione formano un grafo di derivazione ® ® ® se ogni classe ha una sola classe base il grafo è un albero se le classi hanno più classi base il grafo è un DAG il grafo di derivazione non può mai contenere cicli ü Ogni classe del grafo contiene tutti gli elementi che sono comuni a tutte le sue classi derivate Laboratorio di Algoritmi e Strutture Dati 2000-01 specifica del nome delle classi da cui devono essere ereditati dati e metodi. All’interno della classe devono essere definiti i membri aggiuntivi Laboratorio di Algoritmi e Strutture Dati 2000-01 Definizione di una Classe Derivata Laboratorio di Algoritmi e Strutture Dati 2000-01 1 5 1 Derivazione di Classi Esempio Derivazione Singola Esempio Derivazione Multipla rettangolo Panda Orso Felino Pesce OrsoBianco Grizzly Yoghi 6 ü I membri della classe base rappresentano ® Insieme delle operazioni supportate da tutte le classi derivate w L’utente opererà solo sull’interfaccia della classe base w Se l’implementazione dipende dalla classe derivata la funzione è dichiarata virtuale (virtual ) ® Insieme dei dati comuni a tutte le classi derivate w Evita di replicare le definizioni in ciascuna classe derivata w Se le classi derivate devono accedere ad un membro dato è dichiarato protected 7 Esempio Definizione AnimaleZoo class AnimaleZoo { public: AnimaleZoo(char*, char*, short); ~AnimaleZoo(); virtual void disegna(); void localizza(); void informa(); protected: char* nome; char* file; short gabbia; short cont; }; Laboratorio di Algoritmi e Strutture Dati 2000-01 Definizione di una Classe Base 8 ® ® Calcolo del perimetro Settaggio del colore di sfondo e di quello del bordo ü L’implementazione dei metodi per il calcolo dell’area e il disegno del poligono dipendono dal tipo della poligono ü Ogni poligono è rappresentato da ® ® ® Lista dei vertici Colore di sfondo Colore del bordo 9 Interfaccia Pubblica di Poligono Laboratorio di Algoritmi e Strutture Dati 2000-01 Definizione della classe Poligono ü Tutti i tipi di poligoni hanno in comune tre metodi Laboratorio di Algoritmi e Strutture Dati 2000-01 rombo Uccello Laboratorio di Algoritmi e Strutture Dati 2000-01 quadrato cerchio AnimaleZoo Estinzione Erbivoro 10 Laboratorio di Algoritmi e Strutture Dati 2001-02 class Poligono { public: Poligono(); Poligono(int N, vector<Punto>&); // Crea un poligono con N lati memorizzati nel vettore virtual double area() const; double perimentro() const; void setta_sfondo(colore); // Non implementato void setta_bordo(colore) // Non implementato virtual void disegna() const; // Non implementato … }; Laboratorio di Algoritmi e Strutture Dati 2000-01 poligono Laboratorio di Algoritmi e Strutture Dati 2000-01 figura 11 2 Derivazione di Classi Laboratorio di Algoritmi e Strutture Dati 2000-01 double Poligono::perimetro() const { double ris=0.0; for(int i=0; i<_numLati; i++) ris += _lunghezza(_punti[i], _punti[(i+1) % _numLati]); return ris; } 12 13 Definizione di una Classe Derivata ü All’interno della classe devono essere definiti ® I membri aggiuntivi ® I metodi che devono essere modificati 14 class Quadrato : public Poligono { public: … void disegna(); double area(); }; class Rettangolo : public Poligono { public: … void disegna(); double area(); protected: double _altezza, larghezza; }; double Quadrato::area() { double _lato = _lunghezza(_vertici[0], _vertici[1]); return _lato * _lato; double Rettangolo::area() { return _altezza * _larghezza; } } 15 Accesso con Operatore di Scope ü Un oggetto di una classe derivata contiene un sotto- ü I membri ereditati continuano a far parte di un ® Contiene tutti i membri non-static della classe base ü La classe derivata può accedere ai dati non privati della classe base come se fossero propri membri ü I dati privati sono presenti ma non visibili ® Il compilatore segnala un accesso illegale Quadrato *q; q→ area(); // accede a Quadrato::area() q→ perimetro(); // accede a Poligono::perimetro() Laboratorio di Algoritmi e Strutture Dati 2000-01 Accesso ai Membri Ereditati oggetto della sua classe base 16 Laboratorio di Algoritmi e Strutture Dati 2001-02 Laboratorio di Algoritmi e Strutture Dati 2000-01 definizione di una classe derivata richiede la specifica del nome delle classi da cui devono essere ereditati dati e metodi Laboratorio di Algoritmi e Strutture Dati 2000-01 ü La Classi Derivate da Poligono oggetto della classe base e possono essere anche referenziati tramite l’operatore di scope :: q→ Poligono::perimetro(); ü L’operatore di visibilità è necessario quando ® il membro ereditato è stato ridefinito nella classe derivata ® quando la classe eredita da classi base diverse membri con lo stesso nome Laboratorio di Algoritmi e Strutture Dati 2000-01 class Poligono { … protected: int _numLati; vector<Punto> _vertici; color _sfondo; color _bordo; _lunghezza(const Punto&, const Punto&); }; Laboratorio di Algoritmi e Strutture Dati 2000-01 Definizione metodo: perimetro Rappresentazione Poligono 17 3 Derivazione di Classi Accesso ai Membri Protetti della Classe Base bool Quadrato::ConfrontaLati(const Poligono* pp) { int MieiLati = _NumLati; int SuoiLati = pp→ → _NumLati; // ERRORE, accesso a dato protected // Versione corretta: SuoiLati = pp→ GetLati(); return (MieiLati == SuoiLati ); } /* ConfrontaLati e GetLati dovrebbero essere definite nelle classi Poligono e Quadrato */ accesso anche ai membri di B ereditati da altre classi class AnimaleZoo { friend void prezzo(AnimaleZoo&); int valore; … }; class Orso : public AnimaleZoo { int eta; … }; void prezzo(AnimaleZoo& a) { Orso tmp; tmp.valore; // legale tmp.eta; // illegale } 18 ü Un oggetto di una classe derivata contiene sotto- class AnimaleZoo { friend void prezzo(AnimaleZoo&); … }; class Primati : public AnimaleZoo { friend class AnimaleZoo; friend void capacitaParola(Primati&); … }; La funzione prezzo non può accedere ai dati privati di Primati La funzione capacitaParola non può accedere ai membri privati della classe base AnimaleZoo Laboratorio di Algoritmi e Strutture Dati 2000-01 ü La relazione di amicizia non è transitiva gli amici degli amici non sono miei amici 19 Inizializzazione delle Classi Derivate Derivazione ed Amicizia ® oggetti ereditati dalle sue classi base ® Questi sotto-oggetti sono inizializzati dai loro costruttori ü L’inizializzazione di un oggetto della classe derivata avviene in tre passi. Sono invocati: 2. I costruttori delle classi base, per inizializzare i sotto-oggetti ereditati I costruttori delle classi membro definiti nella classe 3. Il costruttore della classe derivata 1. 1. Questo accade quando un dato membro è di tipo classe 20 Inizializzazione delle Classi Derivate Il sotto-oggetto viene identificato tramite il nome della classe base ü I costruttori delle classi base sono chiamati nell’ordine in cui le classi sono specificate nella lista di derivazione Quadrato::Quadrato(const double lato): Poligono(lato,4) {}; ü Il costruttore di Quadrato non deve inizializzare i dati ereditati da Poligono: ® Non si potrebbe modificare la classe Poligono senza modificare anche il codice di Quadrato Laboratorio di Algoritmi e Strutture Dati 2000-01 ® 21 Costruttori Classe Poligono ü Gli argomenti da passare ai costruttori delle classi base sono indicati nella lista di inizializzazione Laboratorio di Algoritmi e Strutture Dati 2000-01 Rispetto ad altri oggetti della classe base si comporta come un oggetto esterno (non può accedere alla parte protetta) Laboratorio di Algoritmi e Strutture Dati 2000-01 ® ü Una funzione amica di una classe B ha privilegio di 22 Laboratorio di Algoritmi e Strutture Dati 2001-02 class Poligono { public: Poligono(); protected: Poligono(const vector<Punto> &); Poligono(double L, int N) // crea un poligono di N lati lunghi L }; Poligono::Poligono() : _NumLati(0), _vertici(), _Sfondo(Bianco), _Bordo(Nero) { } Poligono::Poligono(double val, int lati) : _NumLati(lati), _vertici(lati), _Sfondo(Rosso), _Bordo(Azzurro) { // calcola vertici } Poligono::Poligono(const vector<Punto> & pol) : _vertici(pol), _Sfondo(Verde), _Bordo(Giallo) {_NumLati=pol.size(); } Laboratorio di Algoritmi e Strutture Dati 2000-01 membri protetti del suo sotto-oggetto della classe base Laboratorio di Algoritmi e Strutture Dati 2000-01 ü Un oggetto di una classe derivata può accedere solo ai Derivazione ed Amicizia 23 4 Derivazione di Classi Costruttori per Copia di Classi Derivate Costruttori Classi Derivate ® ® il costruttore di default inizializza membro a membro l’inizializzazione delle parti ereditate dalle classi base è fatta dai costruttori per copia delle classi base i costruttori sono chiamati nell’ordine in cui sono specificate le classi base nella lista di derivazione ü Se la classe contiene la propria versione del costruttore per copia questo costruttore dovrà assegnare i valori ai dati ereditati dalle classi base (inizializzate per default) ü Analogo per l’assegnamento 24 Distruttori Classi Derivate Laboratorio di Algoritmi e Strutture Dati 2000-01 Il compilatore invoca automaticamente i distruttori dei membri e delle classi base ® Non c’è bisogno di invocare esplicitamente questi distruttori ® 25 Esempio: la Classe Panda ü Quando un oggetto di una classe derivata termina il suo tempo di vita deve essere distrutto ü Consideriamo come viene inizializzato un oggetto di tipo Panda ® ® ® ® ® chiama il costruttore di AnimaleZoo chiama il costruttore di Orso chiama il costruttore di Erbivoro chiama il costruttore di Estinzione chiama il costruttore di Panda per assegnare valori agli elementi specifici di Panda ü Le chiamate ai distruttori sono in ordine inverso 26 Livello di Accesso della Derivazione ü Una Il livello di accesso determina la visibilità dei membri ereditati all’interno della classe derivata ü Ogni membro non privato della classe base ha il livello di accesso più restrittivo tra quello che aveva nella classe base e quello della derivazione ® ® ® Derivazione public: ogni elemento ereditato conserva il livello di accesso della classe base Derivazione protected: tutti i membri ereditati sono protected Derivazione private: tutti i membri ereditati sono private Laboratorio di Algoritmi e Strutture Dati 2000-01 ® 27 Derivazione Pubblica ü Ogni derivazione ha un livello di accesso che può essere public, private o protected Laboratorio di Algoritmi e Strutture Dati 2000-01 ® Laboratorio di Algoritmi e Strutture Dati 2000-01 Rettangolo::Rettangolo (double d1, double d2, vector<Punto>& v) : Poligono(v ) { _altezza = d1; _larghezza = d2; } inizializzato per copia anche se non esiste la versione del costruttore per copia 28 Laboratorio di Algoritmi e Strutture Dati 2001-02 derivazione public implementa relazione di specializzazione (isa) ® ® una tutti i metodi pubblici della classe base fanno parte dell’interfaccia pubblica della classe derivata è possibile convertire un oggetto della classe derivata nella classe base ü La derivazione pubblica è usata per ereditare l’interfaccia pubblica della classe base ® La classe derivata può essere utilizzata allo stesso modo delle classi basi, più altri modi specifici Laboratorio di Algoritmi e Strutture Dati 2000-01 Rettangolo::Rettangolo () {_altezza = _larghezza = 0;} ü Un oggetto di una classe derivata può essere Laboratorio di Algoritmi e Strutture Dati 2000-01 class Rettangolo { public: Rettangolo(); Rettangolo (double, double, vector<Punto>&); … }; 29 5 Derivazione di Classi Derivazione Privata Eccezioni della Derivazione ® Nessun membro pubblico della classe base fa parte dell’interfaccia pubblica della classe derivata per convertire un oggetto della classe derivata nella classe base serve un cast ü La derivazione privata è usata per ereditare l’implementazione della classe base ® ® La classe derivata contiene tutti i membri non privati della classe base Possibile ottenere lo stesso risultato inserendo nella classe derivata un membro dato della classe base (contenimento) accesso diverso da quello definito dalle regole standard ® consentire che un metodo di una classe ereditata privatamente sia public ü Non è possibile assegnare ad un membro un livello di accesso più permissivo di quello che aveva nella classe base template <class T> class Stack : private Array<T> { public: Array<T>::lenght; // la funzione lenght di Array<T> è public … }; 30 31 Risoluzione dei Nomi in una Gerarchia di Classi ü Ogni oggetto, riferimento o puntatore ad una classe ü Il campo di visibilità di una classe derivata è derivata può essere convertito in un oggetto, riferimento o puntatore ad una delle sue classi base void ruota(const Poligono&); … rettangolo q(10, 20); ruota(q); // accede solo ai dati ereditati da Poligono ü Ogni puntatore ad un membro di una classe base può essere convertito in un puntatore ad un membro di una classe derivata pubblicamente Laboratorio di Algoritmi e Strutture Dati 2000-01 Conversioni Standard e Derivazioni contenuto nei campi di visibilità delle sue classi base ü Risoluzione dell’identificatore prova contenuto nella funzione Panda::letargo() ® cerca nel campo di visibilità di Panda::letargo ® cerca nel campo di visibilità di Panda ® cerca contemporaneamente nel campo di visibilità di Orso, Erbivoro ed Estinzione ® cerca nel campo di visibilità di AnimaleZoo ® cerca nel campo di visibilità globale Laboratorio di Algoritmi e Strutture Dati 2000-01 ® Laboratorio di Algoritmi e Strutture Dati 2000-01 contenimento (hasa) Laboratorio di Algoritmi e Strutture Dati 2000-01 ü E’ possibile specificare per un membro ereditato un livello di ü Una derivazione private implementa una relazione di ü Se trova più soluzioni contemporaneamente da errore di 32 ambiguità 33 ü Una classe derivata eredita tutti i metodi della sua classe base tranne i costruttori, il distruttore e l’operatore di assegnamento ü Non è possibile sovrapporre all’operatore ereditato dalla classe base una versione locale alla classe derivata, anche se ha firma differente ® il nome dell’operatore è risolto sulla base dei campi di visibilità, senza tener conto dei tipi Laboratorio di Algoritmi e Strutture Dati 2000-01 Ereditarietà di Operatori 34 Laboratorio di Algoritmi e Strutture Dati 2001-02 6