Introduzione all’ereditarietà

In precedenza abbiamo visto che è possibile modellare la realtà di interesse evidenziando gli elementi del sistema (classi), la loro struttura interna (attributi) e le operazioni che sono in grado di compiere (metodi). Tuttavia nel modello non è presente alcuna traccia delle relazioni tra le classi. Ad esempio possiamo aver definito la classe Camion e la classe Ruota, senza aver evidenziato in modo esplicito il fatto che un camion possiede delle ruote. Un sistema orientato agli oggetti è costituito da classi che collaborano tra loro scambiandosi messaggi: quando l'istanza di una classe (oggetto) passa messaggi all'istanza di un'altra classe, tra le due classi esiste certamente una relazione. All’interno dei modelli object-oriented riveste una rilevanza fondamentale la relazione di generalizzazione/specializzazione, detta anche relazione di ereditarietà. Attraverso il processo di generalizzazione si può giungere alla definizione di una classe come unione di un insieme di classi, ognuna delle quali è contenuta nella classe data. Per esempio la classe Persona è una generalizzazione delle due classi Uomo e Donna. Queste ultime, a loro volta, sono sottoinsiemi della classe Persona. Più in generale, si ha una relazione di generalizzazione tra due classi C1 e C2 quando la classe C2: • presenta tutte le caratteristiche e i comportamenti della classe C1; • è più specializzata della classe C1, ossia offre ulteriori funzionalità o la sua struttura è maggiormente dettagliata. La classe C1 viene detta classe base o superclasse o classe padre; la classe C2 prende il nome di classe derivata o sottoclasse o classe figlia. In altre parole, la classe derivata eredita dalla classe base tutti gli attributi e i metodi e può, inoltre, specificarne di ulteriori. Nei sistemi object-oriented, le relazioni di generalizzazione sono appunto modellate mediante il meccanismo dell’ereditarietà. La rappresentazione grafica di questo tipo di relazioni, utilizzando il formalismo UML, è la seguente:

Figura 1 - Rappresentazione UML della relazione di ereditarietà

Bocchi Cinzia Ultimo aggiornamento: 20/11/2012

1

Le classi sono connesse da archi orientati che vanno dalla classe derivata alla classe base.

Esempio

Figura 2 - Esempio di ereditarietà singola

Le relazioni di generalizzazione-specializzazione tra classi individuano una gerarchia: le classi in cima alla gerarchia sono le più generali e, man mano che si scende, si trovano classi più specializzate. La proprietà peculiare di tale relazione prevede che un qualsiasi oggetto istanza di una classe “specializzata” possa essere sempre utilizzata ovunque compaia la classe “base”. Ciò equivale a dire, per esempio, che un oggetto della classe “Uomo” può essere sempre sostituito ad un oggetto della classe “Persona”. Non vale, ovviamente, il viceversa: una persona non è detto che sia un uomo perché potrebbe essere una donna.

Tipi di ereditarietà

Esistono due tipi di ereditarietà: • singola; • multipla. Si ha ereditarietà singola quando una classe è derivata da un’unica superclasse, come mostra la figura1. Si ha ereditarietà multipla quando una classe può essere derivata da due o più sopraclassi. come mostrato nella figura 3. In entrambi i casi, da ogni superclasse possono essere derivate più sottoclassi. L’ereditarietà multipla non è prevista da tutti i linguaggi di programmazione a oggetti (Java, per esempio, non la consente).

Bocchi Cinzia Ultimo aggiornamento: 20/11/2012

2

Figura 3 - Esempio di ereditarietà multipla

Overriding di metodi

Una classe derivata contiene tutti i membri della classe base e possiede, quindi, la sua stessa interfaccia: tutti i messaggi che si possono inviare alla classe base, possono essere inviati anche alla classe derivata. Se si eredita una classe senza fare niente altro o al più aggiungendo solo qualche attributo, gli oggetti della classe derivata hanno lo stesso comportamento della classe base, e questo non è particolarmente interessante. Sicuramente più degno di nota è il caso in cui la classe derivata si diversifica nel comportamento, dalla classe base. I modi per diversificare una classe derivata da una classe base sono due: 1. per estensione, aggiungendo alla classe derivata nuovi metodi, non presenti nella classe base; 2. per ridefinizione, modificando, nella classe derivata, il codice di alcuni metodi della classe base, in modo da cambiarne il comportamento, lasciandone però invariato la firma. La ridefinizione dei metodi nella classe derivata prende in nome di overriding dei metodi. Osserviamo che, nel secondo caso, classe base e classe derivata hanno la stessa interfaccia, anche se il codice dei metodi può essere diverso. Nel definire una classe derivata, si può utilizzare una combinazione dei due metodi precedenti.

Vantaggi dell’ereditarietà

L’ereditarietà consente di riutilizzare il codice scritto in precedenza: le classi derivate, infatti, contengono solo la definizione degli attributi e dei metodi che non appartengono alla classe base o eventualmente una ridefinizione di alcuni metodi della classe base. Se quest’ultima viene modificata, le classi derivate riflettono gli stessi cambiamenti.

Quest'opera è stata rilasciata con licenza Creative Commons Attribution-ShareAlike 3.0 Unported. Per leggere una copia della licenza visita il sito web http://creativecommons.org/licenses/by-sa/3.0/ o spedisci una lettera a Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
Bocchi Cinzia Ultimo aggiornamento: 20/11/2012

3

Sign up to vote on this title
UsefulNot useful