Ereditarietà multiplaAlcuni linguaggi di programmazione permettono di utilizzare l'ereditarietà multipla, in cui una classe può ereditare funzionalità e caratteristiche da più di una classe base. Questa tecnica si contrappone all'ereditarietà singola, in cui una classe può ereditare da una, e solo una, classe base. Nella programmazione orientata agli oggetti, l'ereditarietà descrive una relazione gerarchica fra due classi, nella quale una (quella che eredita) è chiamata "classe derivata" (o "classe figlia", o "sottotipo"), e l'altra (quella da cui si eredita) è chiamata "classe genitrice" (o "classe base", o "superclasse"). Le funzionalità ereditate dalla "figlia" permettono agli oggetti istanziati su di essa di condividere le funzionalità della "genitrice", cioè della classe base. Per esempio: supponiamo di aver creato una classe:
Problema del diamanteL'ereditarietà multipla può essere causa, in alcuni contesti, di qualche confusione, tanto che alcuni ritengono che gli inconvenienti siano maggiori dei benefici. Una possibile causa di ambiguità è la seguente: se due classi B e C ereditano dalla classe A e la classe D eredita sia da B che da C, se un metodo in D chiama un metodo definito in A, da quale classe viene ereditato? Tale ambiguità prende il nome di problema del diamante (in inglese diamond problem), a causa della forma del diagramma di ereditarietà delle classi, simile ad un diamante. Differenti linguaggi di programmazione hanno risolto quest'inconveniente in modi diversi. Implementazione in alcuni linguaggiJava e .NETIn Java si è adottato questo compromesso: una classe può ereditare le interfacce da più di una classe base – cioè esporre all'esterno gli stessi metodi delle interfacce delle classi base – ma può ereditare i dati ed i metodi effettivi da una sola classe base. Anche i linguaggi della piattaforma Microsoft .NET, come C# e Visual Basic utilizzano lo stesso approccio. Dalla versione Java 8, tuttavia, si sono introdotti i modificatori "default" che se associati a metodi di interfacce permettono (al contrario dei metodi senza questo modificatore) non solo di dichiarare ma anche di implementare in modo differente gli stessi metodi nelle interfacce. È comunque d'obbligo l'override dei metodi nelle sottoclassi che implementano entrambe le interfacce, ma tramite un'istruzione ben definita si può invocare un preciso metodo implementato di una specifica interfaccia genitrice. Così nel caso del problema del diamante la classe D effettua l'override del metodo in comune a B e C definito in A e invoca lo specifico metodo di B o C. C++C++ per default segue ogni percorso di ereditarietà separatamente, quindi l'oggetto D contiene due separati oggetti di A e gli usi dei membri di A devono essere opportunamente qualificati. Se l'ereditarietà da A a B e l'ereditarietà da A a C sono entrambe segnate come "virtual" ("class B : virtual A"), C++ si prende particolare cura di creare solo un oggetto A, l'utilizzo dei membri di A funziona correttamente. Se l'ereditarietà virtuale e l'ereditarietà non virtuale sono mischiate, esiste solo un A virtuale e un A non virtuale per ogni percorso di ereditarietà non virtuale a A. EiffelIn Eiffel le classi derivate adattano le funzionalità ereditate rinominandole o definendo anticipatamente le regole per risolvere le ambiguità e decidere quale versione applicare (quella ereditata o quella della classe base). REALbasicAnalogamente a Java anche in REALbasic si possono ereditare metodi e dati da una sola classe base, e, in più, sono previsti metodi aggiuntivi per "estendere" le funzionalità di una classe senza dover ricorrere all'ereditarietà. PerlIn Perl le classi da cui ereditare sono disposte in una lista ordinata, e viene poi chiamato il primo metodo trovato in ordine gerarchico di profondità della prima classe della lista, e così di seguito per le classi successive e per le loro rispettive classi base. PythonPython supporta una forma di ereditarietà multipla, e viene chiamato un metodo attraverso la regola prima-in-profondità, da-sinistra-a-destra. Perciò, se un attributo non viene trovato nella classe derivata, viene cercato nella prima classe base, poi (ricorsivamente) nelle classi base di quest'ultima e, solo se non vi è stato trovato, viene ricercato nella seconda classe base della classe derivata, e così via. EsempioEcco un esempio di ereditarietà multipla in C++: class A
{
protected:
int i;
public:
int get_i() {return i;}
void set_i(int n) {i=n;}
};
class B
{
protected:
int j;
public:
int get_j() {return j;}
void set_j(int n) {j=n;}
};
class C : public A, public B
{
protected:
int k;
public:
int get_k() {return k;}
void set_k(int n) {k=n;}
};
In questo caso, Voci correlate
Collegamenti esterni
|
Portal di Ensiklopedia Dunia