Ereditarietà multipla C++ method vs Twin-Objects

Slides:



Advertisements
Presentazioni simili
Linguaggio C e C++.
Advertisements

Programmazione ad oggetti
Progettazione dei Sistemi Interattivi (A.A. 2004/05) - Lezione 2 1 Progettazione e Sviluppo di Software ad Oggetti 4 OBJECT-ORIENTED ANALYSIS Processo.
© 2007 SEI-Società Editrice Internazionale, Apogeo Unit à B2 Gli oggetti: concetti avanzati.
Costruttori e Distruttori
Recupero debito quarto anno Primo incontro
Recupero debito quarto anno Secondo incontro
Informatica Recupero debito quarto anno Terzo incontro.
Differenze nei vari linguaggi di Elisa Trifirò e Barbara Tacchino
1 Astrazioni sui dati : Specifica ed Implementazione di Tipi di Dato Astratti in Java.
1 Semantica Operazionale di un frammento di Java: lo stato.
Classi ed Oggetti in Java (Cenni). Richiami Ruolo delle Classi in Java Oggetti.
Le gerarchie di tipi.
Metodologie di Programmazione = decomposizione basata su astrazioni
LIP: 1 Marzo 2005 Classe Object e Vettori. Partiamo da Lesercizio dellultima esercitazione realizzato tramite array Vedremo come si puo fare in modo piu.
Fondamenti di Informatica II Ingegneria Informatica / Automatica (A-I) Meccanica Prof. M.T. PAZIENZA a.a – 3° ciclo.
1 Programmazione ad oggetti in Java E.Mumolo, DEEI
Laboratorio di Linguaggi lezione VI: puntatori 2/3 Marco Tarini Università dellInsubria Facoltà di Scienze Matematiche, Fisiche e Naturali di Varese Corso.
Introduzione al linguaggio Java
Derivazione tra classi
Overriding.
Approfondimento delle classi
1 Le gerarchie di tipi. 2 Supertipi e sottotipi 4 un supertipo –class –interface 4 può avere più sottotipi –un sottotipo extends il supertipo ( class.
nome: sequenza di caratteri usata per denotare un oggetto
memoria gestita staticamente:
Lab. Calc. 2005/06 Ereditarietà. Lab. Calc. 2005/06 Scopo di questa lezione: Imparare a creare nuove classi ereditando da classi già esistenti. Capire.
1 laboratorio di calcolo II AA 2003/04 quinta settimana a cura di Domizia Orestano Dipartimento di Fisica Stanza tel. ( )
1 Ereditarietà Una classe può essere derivata da una classe esistente usando la sintassi: public, protected e private specificano il tipo di accesso ai.
Le classi Definizione di classe Attributi e metodi di una classe Costruttori e distruttori Private e public Funzioni friend Il puntatore this.
Sistemi Operativi GESTIONE DEI PROCESSI.
Java base IV: Java e la programmazione O.O.
AN FI Un denominatoe comune Comandi u notazioni che esprimono azioni che, una volta eseguite, comportano una modifica permanente dello stato interno.
IL TEMA DELLA RIUSABILITÀ Si vuole riusare tutto ciò che può essere riusato (componenti, codice, astrazioni) Non è utile né opportuno modificare codice.
IL TEMA DELLA RIUSABILITÀ Si vuole riusare tutto ciò che può essere riusato (componenti, codice, astrazioni) Non è utile né opportuno modificare codice.
Elementi di programmazione ad oggetti a. a. 2009/2010 Corso di Laurea Magistrale in Ingegneria Elettronica Docente: Mauro Mazzieri, Dipartimento di Ingegneria.
Programmazione in Java (8)
Ereditarietà e Polimorfismo
Introduzione alla programmazione Object Oriented
Enumerazioni e Classi 1. Enumerazioni Permettono di definire nuovi tipi che consistono in un insieme di valori costanti (ognuno con un nome) – Migliorano.
1 Lucidi delle esercitazioni di Sistemi di Elaborazione in Rete Università degli Studi della Calabria Corso di Laurea in Ingegneria Gestionale A.A. 2003/2004.
ISTITUTO STATALE DI ISTRUZIONE SUPERIORE F. ENRIQUES CORSO JAVA – PROVA INTERMEDIA DEL 12 MARZO 2007 NOME: COGNOME: ________________________________________________________________________________.
I nomi in Java F. Bombi 18 novembre novembre 2003.
1 cin>>c8 s.r.l A.A Generalità Uno dei concetti largamente adottati negli ultimi anni dai professionisti del software in fase di sviluppo.
Fondamenti di Informatica 2 Ingegneria Informatica Docente: Giovanni Macchia a.a
CORSO DI PROGRAMMAZIONE II Lezione 22
Oggetti in C# Lezione 5 Polimorfismo I Andrea Zoccheddu.
Programmazione ad oggetti
Vettori, indirizzi e puntatori Finora abbiamo usato gli indirizzi nel chiamare  la funzione scanf()  le altre funzioni per riferimento Tuttavia la vera.
Ereditarieta’. Contenuti Introduciamo un meccanismo fondamentale di Java: l’ereditarieta’ Permette di estendere classi gia’ definite (ovvero di definire.
1 Osservazioni Generali Struttura di programma Gerarchia di classi: overloading, overriding, e dispatching Analisi ed esecuzione Modificabilità e condivisione.
Fondamenti di Informatica II Ingegneria Informatica Prof. M.T. PAZIENZA a.a – 3° ciclo.
Fondamenti di Informatica II Ingegneria Informatica (A-I) Prof. M.T. PAZIENZA a.a – 3° ciclo.
Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 7 Tipi di dato e strutture dati Specifica e realizzazione di strutture informative come classi.
Fondamenti di Informatica 2 Ingegneria Informatica Docente: Giovanni Macchia a.a
OBJECT ORIENTED DATABASE introduzione. OGGETTO Ha due componenti:  stato: valore di alcune variabili (variabili di istanza)  comportamento: insieme.
Programmazione in Java. Classi I programmi in Java consistono di classi. Le classi consentono di definire: collezioni di procedure (metodi statici) tipi.
Cose nuove di Java (prima a chiacchiera, poi formalmente)
Ereditarieta’. Contenuti Introduciamo un meccanismo fondamentale di Java: l’ereditarieta’ Permette di estendere classi gia’ definite (ovvero di definire.
Sommario Oggetti immutabili e non Tipi Primitivi: String, Arrays.
Ereditarieta’. Contenuti Introduciamo un meccanismo fondamentale di Java: l’ereditarieta’ Permette di estendere classi gia’ definite (ovvero di definire.
Progettare una classe 21 Febbraio La classe BankAccount Vogliamo realizzare una classe i cui oggetti sono dei semplici conti bancari. * Identifichiamo.
1 Metodologie di Programmazione = decomposizione basata su astrazioni.
Esercitazione del 9 marzo 2007 Ereditarieta’. Richiami Definire sottoclassi (ereditarieta’) Overriding Specificatori di accesso (private, protected) Principio.
LIP: 4 Maggio 2007 Interfacce. Cos’e’ una Interfaccia una interfaccia e’ un particolare tipo di classe contiene solo la specifica non ha implementazione.
Corso di Algoritmi e Strutture Dati con Laboratorio Richiami di Java – parte II.
28/12/2001package 1 Package Pacchetti e interfacce.
Introduzione all’Ereditarietà Pietro Palladino. Richiami UML Classe: descrizione di un insieme di oggetti software con caratteristiche simili Definisce.
Introduzione alle Classi e agli Oggetti in Java 1.
Transcript della presentazione:

Ereditarietà multipla C++ method vs Twin-Objects Daniela Briola Orlin Velinov

Ereditarietà singola A B Nell’esempio la classe B è derivata dalla classe A. Ogni linguaggio Object Oriented supporta il concetto di ereditarietà Si dice che una classe è derivata da un’altra quando ne estende le funzionalità grazie all’inheritance

Ereditarietà multipla Permette di comporre classi derivando da più classi base. A B C

Ereditarietà multipla Vantaggi Svantaggi Complicazione notevole del linguaggio che la implementa Possibilità di comporre velocemente oggetti molto complessi Aggregare funzionalità differenti in un’unica classe Scarsa efficienza anche quando non viene usata Soluzione elegante e di grande utilità Rischio elevato di “name clash”

Ereditarietà multipla: il problema del diamante Se una classe eredita membri con lo stesso nome da più di un genitore, avviene un conflitto A B1 B2 C ? Ci sono due strategie possibili: gestire direttamente il grafo di ereditarietà trasformarlo in una catena lineare (ereditarietà singola)

Ereditarietà multipla: il problema del diamante La semantica dei linguaggi orientati al grafo modella direttamente l’albero di derivazione Se un membro è definito solo dalla classe A, è ereditato da B1 e da C senza errori Si deve prevedere il caso di ridefinizione dei metodi doppi da parte di B2 A B1 B2 C

Ereditarietà multipla: il problema del diamante Soluzione Lineare: La gerarchia di derivazione viene linearizzata Si elimina l’invocazione multipla di metodi della soluzione precedente Svantaggi Lo sviluppatore non è al corrente della gerarchia di sottotipazione implicita La selezione del metodo da utilizzare è a discrezione del compilatore Problemi nel collegamento con il genitore effettivo A B2 B1 C

Ereditarietà multipla Implementazione C++

C++ Ereditarietà singola In C++ una oggetto è una regione di memoria contigua class A { int a; void f(int i); }; int a A* pa; pa->f(2); Nell’area di memoria riservata all’oggetto pa viene solo salvato un intero La funzione f, essendo non-virtual (statica), è definita esternamente all’oggetto pa, quindi è come fosse una funzione/procedura normale.

C++ Ereditarietà singola Gli oggetti composti (derivati) sono costruiti dal compilatore concatenando le aree di memoria. int a class A { int a; void f(int); }; class B : A { int b; void g(int); }; class C : B { int c; void h(int); }; int b int c Se la classe definisce metodi virtual entra in gioco la tabella delle funzioni (VMT): ogni oggetto ha un puntatore alla VMT, che permette di identificare la funzione effettivamente da usare.

C++ Polimorfismo Il polimorfismo è un concetto fondamentale della programmazione OO Consente che gli oggetti assumano comportamenti differenti a seconda del contesto in cui operano In particolare se Ptr è un puntatore di tipo T, allora Ptr può puntare non solo a istanze di tipo T ma anche a istanze di classi derivate da T T* Ptr = 0; // Puntatore nullo /* ... */ Ptr = new Td; // Td è una classe derivata da T

C++ Polimorfismo (2) C++ fa in modo che il corretto tipo dell’oggetto venga determinato automaticamente alla chiamata della funzione In questo modo il linking della funzione viene rimandato a runtime (binding dinamico) Per fare ciò bisogna dichiarare la funzione membro virtual class T { public: virtual void Paint(); };

C++ Polimorfismo: Implementazione I metodi virtuali vengono ereditati allo stesso modo di quelli non virtual, possono anch'essi essere sottoposti a overloading ed essere ridefiniti non c'e` alcuna differenza eccetto che una loro invocazione viene risolta a run-time In una classe con un metodo virtuale, il compilatore associa alla classe (non all'istanza) una tabella (VMT) che contiene per ogni metodo virtuale l'indirizzo alla corrispondente funzione Ogni istanza di quella classe conterrà poi al suo interno un puntatore (VPTR) alla VMT

C++ Polimorfismo: Overhead L'invocazione di un metodo virtuale e` piu` costosa di quella per una funzione membro ordinaria, tuttavia il compilatore puo` evitare tale overhead risolvendo a compile-time tutte quelle situazioni in cui il tipo e` effettivamente noto Td Obj1; T* Ptr = 0; Obj1.Paint(); // Chiamata risolvibile staticamente Ptr->Paint(); // Questa invece no

Polimorfismo nell’ereditarietà multipla class A { virtual void f(); }; class B { virtual void f(); virtual void g() }; class C: A, B { void f(); }; A* pa = new C; B* pb = new C; C* pc = new C; pa->f(); pb->f(); pc->f(); C eredita sia da A che da B, dunque l’assegnazione è corretta Tutte tre le chiamate invocano C::f()

C++ Classi astratte Funzioni virtuali pure Ereditarietà e polimorfismo possono essere combinati per realizzare classi il cui unico scopo è creare una interfaccia comune a una gerarchia di classi class TShape { virtual void Paint() = 0; virtual void Erase() = 0; }; Funzioni virtuali pure Una classe che possiede funzioni virtuali pure è detta classe astratta e non è possibile istanziarla Può essere utilizzata unicamente per derivare nuove classi forzandole a fornire determinati metodi

C++ Ereditarietà multipla: Ambiguità Analizziamo il caso in cui la classe D derivi da B1 e B2 class Base1 { public: void f(); }; class Base2 { void f2(); class Derived : Base1, Base2 { // Non ridefinisce f() B1 B2 D La classe Derived eredita piu` volte gli stessi membri, in particolare la funzione f()

C++ Ereditarietà multipla: Ambiguità – soluzione esplicita Derived x; x.f() //Errore, è ambiguo! N.B.: questo è un errore che appare solo a runtime Soluzione: Derived x; x.B1::f() quanto detto vale anche per gli attributi; non è necessario che la stessa definizione si trovi in più classi basi dirette, è sufficiente che essa giunga alla classe derivata attraverso due classi basi distinte il problema non si sarebbe posto se Derived avesse ridefinito la funzione membro f().

C++ Ereditarietà multipla: Ambiguità - Implementazione Come implementa il C++ una soluzione esplicita attraverso qualificatore x.b1::f() ? b1::f() si aspetta un puntatore b1* (che diventa il suo this) A runtime conosciamo però solo il puntatore della classe derivata “derived” Il compilatore aggiunge un opportuno delta (memorizzato nella VMT) per raggiungere la parte relativa a B1 in “derived” In pratica, il compilatore trasforma una chiamata diretta in una indiretta, sommando un offset

C++ Ereditarietà multipla: Implementazione VMT Parte B1 Delta(B2) C::f() Parte B2 C::f() -delta(B2) B2::g() Parte D

C++ Ereditarietà multipla: Ambiguità Il problema dell'ambiguità può essere portato al caso estremo in cui una classe erediti più volte una stessa classe base class Base { }; class Derived1 : Base { }; class Derived2 : Base { }; class Derived3 : Derived1, Derived2 { };

C++ Ereditarietà multipla: Ambiguità Derived3 Derived1 Derived2 ? Base Base

C++ Ereditarietà multipla: Ambiguità – ereditarietà virtuale Il C++ permette di risolvere il problema molto elegantemente con l’uso di classi base virtuali class Base { }; class Derived1 : virtual Base { }; class Derived2 : virtual Base { }; class Derived3 : Derived1, Derived2 { }; Quando una classe eredita tramite la keyword virtual il compilatore non copia il contenuto della classe base nella classe derivata, ma inserisce nella classe derivata un puntatore ad un’unica istanza della classe base

C++ Ereditarietà multipla: Ambiguità – ereditarietà virtuale Derived3 Derived1 virtual Base Derived2

C++ Ereditarietà multipla: Ambiguità – ridefinizione In alcuni casi l’ambiguità persiste. Supponiamo che una delle classi intermedie ridefinisca una funzione membro della classe base. class Base { public: void DoSomething(); }; class Derived1 : virtual Base { class Derived2 : virtual Base { class Derived3 : Derived1, Derived2 { }; Se Derived3 non ridefinisce DoSomething si crea ambiguità! Quale metodo usare? Il compilatore C++ segnala errore!

C++ Ereditarietà multipla: Ambiguità – ridefinizione La situazione è diversa se solo una delle classi intermedie fa la ridefinizione class Base { public: void DoSomething(); }; class Derived1 : virtual Base { class Derived2 : virtual Base { /* … */ }; class Derived3 : Derived1, Derived2 { }; Solo Derived1 ridefinisce DoSomething (definizione dominante) Il compilatore C++ non segnala errore!

C++ Ereditarietà multipla: Ambiguità – Esempio La “virtualità” di una classe non è una sua caratteristica, ma è data dall’essere dichiarata come tale nelle classi che la ereditano. Vediamo un esempio: In questo caso la classe C avrà un solo riferimento ad un oggetto di classe L class A : virtual L {...}; class B : virtual L {...}; class C : A , B {...}; In questo caso invece la classe D avrà due “sotto-oggetti” di tipo L, un virtuale e uno normale class D : L,C{...};

C++ Ereditarietà multipla: i costruttori Le classi derivate normalmente chiamano implicitamente (o esplicitamente) i costruttori delle classi base In caso di ereditarietà multipla con classe base virtuale si pone il problema di decidere chi inizializza la classe base (in quale ordine) In C++ le classi virtual sono inizializzate dalle classi massimamente derivate In generale i costruttori sono eseguiti nell’ordine in cui compaiono nella dichiarazione eccetto quelli delle classi virtual, eseguiti prima

C++ Ereditarietà multipla: i distruttori Stesso discorso per i distruttori, ma in ordine contrario Il compilatore C++ si preoccupa di distruggere le classi virtual una sola volta, anche se vengono ereditate molteplici volte

C++ Ereditarietà multipla: Problemi di efficienza L’ereditarietà multipla comporta alcuni costi in termini di efficienza: Sottrazione di una costante per ogni accesso ai membri delle classi base Un word per funzione in ogni VMT (per il delta) Un riferimento in memoria ed una sottrazione per ogni chiamata a funzione virtuale Un riferimento in memoria ed una sottrazione per ogni accesso ai membri di una classe base virtuale La 1 e la 4 sono penalizzanti solo se l’ereditarietà multipla è effettivamente usata. La 2 e la 3 sempre

C++ Ereditarietà multipla: Considerazioni Il metodo qui presentato offre due modalità di estendere il “name space” di una classe: classe base classe base virtuale Comunque, le regole per gestire questi due tipi di classi sono indipendenti dal tipo di classe effettivamente usata, inoltre: le ambiguità sono illegali le regole per la gestione dei vari membri sono le stesse che con ereditarietà singola le regole di visibilità ed inizializzazione sono le stesse dell’ereditarietà singola Violazioni di queste regole sono segnalate a compile-time

C++ Ereditarietà multipla: Conclusioni L’ereditarietà multipla, in una forma pratica da usare, è relativamente semplice da aggiungere al C++ Per essere implementata richiede piccolissime modifiche alla sintassi e si adatta naturalmente alla già preesistente struttura L’implementazione è efficiente sia in tempo che in spazio, dal momento che, soprattutto su calcolatori moderni, semplici operazioni di somma o sottrazione o un campo in più nella VMT non costituiscono un overhead pesante La compatibilità con il C non è compromessa, e neppure la portabilità

Ereditarietà multipla Implementazione modello “Twin Objects” (J.Templ)

Twin Objects Sono un modo di realizzare l’ereditarietà multipla usando l’ereditarietà singola Possono essere usati per implementare l’ereditarietà multipla in linguaggi che non la supportano, ad esempio in Java Aiutano a risolvere problemi tipici dell’ereditarietà multipla quali l’ambiguità dei nomi

Twin Objects - modello B B CB CA C A C A Multiple Inheritance CA e CB sono chiamati twins (gemelli) Sono sempre generati assieme e legati dai puntatori T1 e T2

Twin Objects - modello B E C A CA CE CB Se la classe C eredita da n classi base, ci saranno n twins da gestire A B E CA CE C CB

Twin Objects - modello P2 C2 C P1 Se dobbiamo inserire nella nostra classe attributi o metodi aggiuntivi (non definiti nelle classi basi) abbiamo due metodi: creiamo una classe aggiuntiva C in cui li inseriamo P1 P2 C2 C T1 T2 li mettiamo in uno dei due twin (ad es. in C1, che chiamiamo C); questo è l’approccio seguito normalmente

Twin Objects - ereditarietà P1 P2 C2 C T1 T2 D2 D1 C2 P1 P2 C T1 T2 D No D non eredita da C2!

Twin Objects - Collaborazione Ogni classe figlio è responsabile per la comunicazione con il suo padre e si occupa di inoltrare i messaggi alle classi gemelle I client referenziano uno dei figli direttamente, e tutti gli altri tramite i puntatori a twin (la ‘T’ negli esempi) I client che necessitano di comunicare con uno dei Padri, lo fanno attraverso la rispettiva classe-figlio

Twin Objects - Implemenazione Astrazione: le classi gemelle devono cooperare strettamente tra loro, permettendo di accedere ai loro membri privati (visibilità package in Java). Il tutto deve apparire come un unico oggetto dall’esterno. Efficienza: l’uso di twin objects sostituisce le relazioni per ereditarietà con relazioni per composizione. Ciò comporta la necessità di inoltrare messaggi e quindi minore efficienza, ma poiché l’ereditarietà multipla è in genere più lenta, non si notano differenze sostanziali.

Twin Objects - Ottimizzazioni Raggruppare i Twin in un unico blocco contiguo per velocizzare l’allocazione dell’oggetto che li usanecessità di utilizzare puntatori nel blocco per collegare i twin sostituire il puntatore con un offset relativo all’inizio del twin se l’allocazione degli oggetti client e dei twin è resa uguale per ogni istanza, l’offset è una costante memorizzabile a parte le VMT possono essere memorizzate contiguamente in un blocco

Twin Objects - Esempio Java non consente l’ereditarietà multipla, tuttavia in alcuni casi serve poter mettere assieme oggetti di natura diversa, ad esempio implementando applet che reagiscono alle azioni del mouse Costruendo un applet, serve poter ereditare da un generico Applet a cui verrà ridefinito il metodo .Paint() e da una classe StdMouseListener di cui verranno ridefiniti i metodi mousePressed(), mouseClicked() e mouseReleased() Lo schema che segue riassume la struttura del nostro oggetto composto MyApplet + MyAppletListener

Twin Objects – Esempio C Applet resize() paint() … StdMouseListener mousePressed() mouseClicked() mouseReleased() paint() C T1 T2 MyApplet mousePressed() mouseClicked() mouseReleased() MyAppletListener

Twin Objects - Esempio class Applet { public void paint(); public void resize(); … } class StdMouseListener { public void mousePressed(); public void mouseClicked(); public void mouseReleased(); … } Queste sono le definizioni delle due classi base di cui desideriamo fare ereditarietà multipla attraverso l’uso del modello Twin Objects

Twin Objects - Esempio class MyApplet extends Applet { MyAppletListener listener; /* il Twin */ public void paint() { /* ridefinisco */ } … } class MyAppletListener extends StdMouseListener { MyApplet applet; /* il Twin */ public void mousePressed () { /* ridefinisco */ } public void mouseClicked () { /* ridefinisco */ } public void mouseReleased () { /* ridefinisco */ } … } Ogni “twin” eredita il proprio parent ridefinendone i metodi opportuni e si occupa di comunicare con il proprio fratello.

Twin Objects - Esempio Layout in memoria: MyApplet Applet MyStdMouseListener StdMouseListener twins Come evidente, si tratta di oggetti completamente separati a livello di memoria. Il link tra le classi è fatto a livello di applicazione.

C++ - Contro esempio class Applet { virtual void paint(); virtual void resize(); … } class StdMouseListener { virtual void mousePressed(); virtual void mouseClicked(); virtual void mouseReleased(); Come per l’esempio Twin Objects, abbiamo due classi base iniziali da cui vogliamo fare ereditarietà multipla... “virtual” indica che le funzioni sono di tipo latebinding (come nell’es. Java) e non statiche.

C++ - Contro esempio class MyApplet : Applet, StdMouseListener { void paint() { /* ridefinisco */ } void mousePressed() { /* ridefinisco */ } void mouseClicked() { /* ridefinisco */ } void mouseReleased() { /* ridefinisco */ } … } Il C++ ci consente di avere un’unica classe MyApplett che eredita contemporaneamente da Applet e StdMouseListener. Ridefinisco i metodi secondo le esigenze; per fortuna non ci sono name clashes quindi non ci preoccupiamo di usare qualificatori espliciti A livello implementativo, il compilatore traduce una chiamata del tipo *obj->paint() in una chiamata indiretta sommando un delta riferito alla classe parent e memorizzato nella VMT

C++ contro esempio VMT Parte Applet Parte Stdmouselistener delta(StdML) Myapp::paint() Parte Stdmouselistener Myapp::paint() -delta(StdML) metodi ridefiniti da MyApplet Parte Myapplet

Considerazioni di Templ sull’ereditarietà multipla L’implementazione dell’ereditarietà multipla del C++ porta ad un overhead anche dell’ereditarietà singola Il codice deve essere riaggiustato per cambiare il “self” L’ereditarietà multipla in se stessa non è né molto utile né veramente necessaria dal momento che può essere facilmente simulata Il vantaggio che offre è puramente sintattico Il suo costo non è giustificato dalle opportunità che offre

Conclusioni L’ereditarietà multipla è uno strumento potente che consente di affrontare problemi complessi con eleganza La sua implementazione nativa può generare un lieve decadimento del performances anche quando non viene usata (vedi C++) Gestire un linguaggio con ereditarietà multipla può divenire comunque complesso e poco chiaro (sia per il programmatore che per l’implementatore) I linguaggi moderni tendono ad evitarla (es. Java), adoperando tecniche altrettanto efficaci come i Twin Objects, senza overhead e complicazioni, dal momento che i vantaggi, sebbene ci siano, forse non giustificano le necessarie modifiche dei linguaggi OO già esistenti

Riferimenti “Twin – A Design Pattern for Modeling Multiple Inheritance” J. Templ “Multiple Inheritance for C++” Bjarne Stroustrup Manuale del C++ Bjarne Stroustrup