Fondamenti di Informatica II Ingegneria Informatica Prof. M.T. PAZIENZA a.a – 3° ciclo
Ereditarietà L’ereditarietà è il meccanismo mediante il quale una classe acquisisce tutte le caratteristiche di un’altra classe definita in precedenza (ereditarietà semplice) La classe che eredita le caratteristiche è chiamata sottoclasse La classe che fornisce le proprie caratteristiche viene chiamata superclasse Una classe può ereditare le proprie caratteristiche da più superclassi (ereditarietà multipla).
Ereditarietà In C++ è possibile progettare (con un processo ricorsivo) nuove classi (classi derivate) a partire da classi già esistenti (classi base). Le classi derivate assimilano attributi e comportamenti di classi base esistenti, eventualmente sovrascrivendo e migliorando le caratteristiche di queste ultime secondo le nuove necessità. La classe derivata può avere dati e funzioni sia ereditati, sia propri; le dimensioni delle due classi possono, così, non coincidere.
Ereditarietà Ogni classe ha una propria vita indipendente; quando si adotta il meccanismo della ereditarietà essa può assumere il ruolo di : 1.classe base che passa i propri attributi e comportamenti ad altre classi, 2.classe derivata che eredita queste caratteristiche da altre classi.
Ereditarietà La classe derivata è più specifica della classe base da cui deriva e rappresenta un insieme di oggetti meno numeroso. Nella ereditarietà semplice la classe derivata rappresenta una versione della classe base. Gli oggetti di una classe derivata possono essere pensati come oggetti delle classi base (=> più oggetti associati alla classe base, meno oggetti alle classi derivate)
Sintassi dei meccanismi di ereditarietà Le modalità di derivazione di una classe da una classe base sono definite tramite lo specificatore di accesso alla classe base. La forma generale per dichiarare che una classe eredita da un’altra è: class nome-classe_derivata: tipo-accesso nome-classe_base { corpo della classe derivata } ; il tipo di accesso può essere private, public, protected
Ereditarietà Quando una classe base viene ereditata come pubblica, tutti i suoi membri pubblici diventano pubblici per la classe derivata, tutti i suoi membri protected diventano protetti per la classe derivata (membri privati per la loro classe, ma ereditabili ed accessibili per una classe derivata), mentre i suoi membri privati sono nascosti alla classe derivata.
Ereditarietà Quando una classe base viene ereditata come privata, tutti i suoi membri pubblici diventano membri privati per la classe derivata, tutti i suoi membri protected diventano membri privati per la classe derivata (membri privati per la loro classe, ma ereditabili ed accessibili per una classe derivata), mentre i suoi membri privati sono nascosti alla classe derivata.
Ereditarietà Quando una classe base viene ereditata come protected, tutti i suoi membri pubblici e protetti diventano protetti per la classe derivata, mentre i suoi membri privati sono nascosti alla classe derivata.
Ereditarietà Se una classe derivata potesse accede ai membri private della propria classe base, si violerebbe l’incapsulamento della classe base. Infatti l’accesso a quei dati sarebbe possibile anche per le classi derivate da tale classe derivata, ecc. Ciò costituirebbe una propagazione dell’accesso a dati che si considerano privati, disperdendo i benefici dell’incapsulamento lungo l’intera gerarchia delle classi.
Ereditarietà Es.: class base { public: void set(int); … protected: int i,j; //privato per base, ma accessibile per derivato } ; class derivato: public base { public: … // può accedere a i e j di base private: int k; } ;
Ereditarietà di tipo public Un oggetto di una classe derivata con ereditarietà di tipo public può essere trattato come un oggetto della sua classe base. Per esempio, anche se oggetti di classi diverse che discendono da una classe base comune possono essere notevolmente diversi tra di loro, si può creare un array che li contenga (avrà come tipo gli oggetti della classe base).
Ereditarietà: costruttori e distruttori Una classe derivata eredita i membri della propria classe base; quando si istanzia un oggetto di una classe derivata occorre chiamare il costruttore della classe base per inizializzarli. Se si omette il costruttore per una classe derivata, il costruttore di default di tale classe chiama il costruttore di default della classe base. I distruttori sono chiamati in ordine inverso rispetto ai costruttori, per cui il distruttore di una classe derivata viene chiamato prima del distruttore della propria classe base.
Ereditarietà public: puntatori 1- accesso ad un oggetto della classe base con un puntatore alla classe base (operazione diretta) 2- accesso ad un oggetto della classe derivata con un puntatore alla classe derivata (operazione diretta) 3- accesso ad un oggetto della classe derivata con un puntatore alla classe base (operazione diretta), però si possono riferire solo membri della classe base e non i membri propri della classe derivata 4- accesso ad un oggetto della classe base con un puntatore alla classe derivata (errore sintassi)
Ereditarietà Ereditarietà singola (la nuova classe deriva da una sola classe base) Ereditarietà multipla (la nuova classe deriva da più classi base anche tra loro scorrelate).
Ereditarietà multipla E’ possibile far derivare una classe da più classi base. Ereditarietà multipla (multiple inheritance) La classe derivata eredita i membri di più classi base. (possibili ambiguità) class nome-classe_derivata: tipo- accesso1 nome-classe_base1, tipo- accesso2 nome-classe_base2,… tipo- accesson nome-classe_basen { corpo della classe derivata } ; tipi di accesso public, private o protected