La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

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

Presentazioni simili


Presentazione sul tema: "Ereditarietà multipla C++ method vs Twin-Objects Daniela Briola Orlin Velinov."— Transcript della presentazione:

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

2 Ereditarietà singola Ogni linguaggio Object Oriented supporta il concetto di ereditarietà Ogni linguaggio Object Oriented supporta il concetto di ereditarietà Si dice che una classe è derivata da unaltra quando ne estende le funzionalità grazie allinheritance Si dice che una classe è derivata da unaltra quando ne estende le funzionalità grazie allinheritance A B A Nellesempio la classe B è derivata dalla classe A. Nellesempio la classe B è derivata dalla classe A.

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

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

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

6 Ereditarietà multipla: il problema del diamante La semantica dei linguaggi orientati al grafo modella direttamente lalbero di derivazione La semantica dei linguaggi orientati al grafo modella direttamente lalbero di derivazione Se un membro è definito solo dalla classe A, è ereditato da B1 e da C senza errori 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 Si deve prevedere il caso di ridefinizione dei metodi doppi da parte di B2 A B1 B2 C

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

8 Ereditarietà multipla Implementazione C++

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

10 int c C++ Ereditarietà singola Gli oggetti composti (derivati) sono costruiti dal compilatore concatenando le aree di memoria. Gli oggetti composti (derivati) sono costruiti dal compilatore concatenando le aree di memoria. 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 a 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. 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.

11 C++ P olimorfismo Consente che gli oggetti assumano comportamenti differenti a seconda del contesto in cui operano 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 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 Il polimorfismo è un concetto fondamentale della programmazione OO Il polimorfismo è un concetto fondamentale della programmazione OO

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

13 C++ P olimorfismo: Implementazione 1.I metodi virtuali vengono ereditati allo stesso modo di quelli non virtual, possono anch'essi essere sottoposti a overloading ed essere ridefiniti 2.non c'e` alcuna differenza eccetto che una loro invocazione viene risolta a run-time 3.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 4.Ogni istanza di quella classe conterrà poi al suo interno un puntatore (VPTR) alla VMT

14 C++ P olimorfismo: 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 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; Td Obj1; T* Ptr = 0; T* Ptr = 0; Obj1.Paint(); // Chiamata risolvibile staticamente Obj1.Paint(); // Chiamata risolvibile staticamente Ptr->Paint(); // Questa invece no Ptr->Paint(); // Questa invece no

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

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

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

18 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; 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 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().

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

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

21 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 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 { };

22 C++ Ereditarietà multipla: Ambiguità Derived3 Derived1Derived2 Base

23 C++ Ereditarietà multipla: Ambiguità – ereditarietà virtuale Il C++ permette di risolvere il problema molto elegantemente con luso di classi base virtuali Il C++ permette di risolvere il problema molto elegantemente con luso 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 ununica istanza della classe base 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 ununica istanza della classe base

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

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

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

27 class A : virtual L {...}; class B : virtual L {...}; class C : A, B {...}; C++ Ereditarietà multipla: Ambiguità – Esempio La virtualità di una classe non è una sua caratteristica, ma è data dallessere 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 D : L,C{...}; In questo caso invece la classe D avrà due sotto- oggetti di tipo L, un virtuale e uno normale

28 C++ Ereditarietà multipla: i costruttori Le classi derivate normalmente chiamano implicitamente (o esplicitamente) i costruttori delle classi base 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 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 C++ le classi virtual sono inizializzate dalle classi massimamente derivate In generale i costruttori sono eseguiti nellordine in cui compaiono nella dichiarazione eccetto quelli delle classi virtual, eseguiti prima In generale i costruttori sono eseguiti nellordine in cui compaiono nella dichiarazione eccetto quelli delle classi virtual, eseguiti prima

29 C++ Ereditarietà multipla: i distruttori Stesso discorso per i distruttori, ma in ordine contrario 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 Il compilatore C++ si preoccupa di distruggere le classi virtual una sola volta, anche se vengono ereditate molteplici volte

30 C++ Ereditarietà multipla: Problemi di efficienza Lereditarietà multipla comporta alcuni costi in termini di efficienza: 1.Sottrazione di una costante per ogni accesso ai membri delle classi base 2.Un word per funzione in ogni VMT (per il delta) 3.Un riferimento in memoria ed una sottrazione per ogni chiamata a funzione virtuale 4.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 lereditarietà multipla è effettivamente usata. La 2 e la 3 sempre

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

32 C++ Ereditarietà multipla: Conclusioni Lereditarietà 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 Limplementazione è 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à

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

34 Twin Objects Sono un modo di realizzare lereditarietà multipla usando lereditarietà singola Sono un modo di realizzare lereditarietà multipla usando lereditarietà singola Possono essere usati per implementare lereditarietà multipla in linguaggi che non la supportano, ad esempio in Java Possono essere usati per implementare lereditarietà multipla in linguaggi che non la supportano, ad esempio in Java Aiutano a risolvere problemi tipici dellereditarietà multipla quali lambiguità dei nomi Aiutano a risolvere problemi tipici dellereditarietà multipla quali lambiguità dei nomi

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

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

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

38 Twin Objects - ereditarietà P1P2 C2C T1 T2 D2D1 T1 T2 C2 P2 C T1 T2 D No D non eredita da C2!

39 Twin Objects - Collaborazione Ogni classe figlio è responsabile per la comunicazione con il suo padre e si occupa di inoltrare i messaggi alle classi gemelle 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 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 I client che necessitano di comunicare con uno dei Padri, lo fanno attraverso la rispettiva classe-figlio

40 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 dallesterno. 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 dallesterno. Efficienza: luso 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é lereditarietà multipla è in genere più lenta, non si notano differenze sostanziali. Efficienza: luso 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é lereditarietà multipla è in genere più lenta, non si notano differenze sostanziali.

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

42 Twin Objects - Esempio Java non consente lereditarietà multipla, tuttavia in alcuni casi serve poter mettere assieme oggetti di natura diversa, ad esempio implementando applet che reagiscono alle azioni del mouse Java non consente lereditarietà 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() 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 Lo schema che segue riassume la struttura del nostro oggetto composto MyApplet + MyAppletListener

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

44 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 luso del modello Twin Objects Queste sono le definizioni delle due classi base di cui desideriamo fare ereditarietà multipla attraverso luso del modello Twin Objects

45 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. Ogni twin eredita il proprio parent ridefinendone i metodi opportuni e si occupa di comunicare con il proprio fratello.

46 Twin Objects - Esempio Layout in memoria: 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. Come evidente, si tratta di oggetti completamente separati a livello di memoria. Il link tra le classi è fatto a livello di applicazione.

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

48 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 ununica classe MyApplett che eredita contemporaneamente da Applet e StdMouseListener. Il C++ ci consente di avere ununica 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 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 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

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

50 Limplementazione dellereditarietà multipla del C++ porta ad un overhead anche dellereditarietà singola Limplementazione dellereditarietà multipla del C++ porta ad un overhead anche dellereditarietà singola Il codice deve essere riaggiustato per cambiare il self Il codice deve essere riaggiustato per cambiare il self Lereditarietà multipla in se stessa non è né molto utile né veramente necessaria dal momento che può essere facilmente simulata Lereditarietà 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 vantaggio che offre è puramente sintattico Il suo costo non è giustificato dalle opportunità che offre Il suo costo non è giustificato dalle opportunità che offre Considerazioni di Templ sullereditarietà multipla

51 Conclusioni Lereditarietà multipla è uno strumento potente che consente di affrontare problemi complessi con eleganza Lereditarietà 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++) 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 limplementatore) Gestire un linguaggio con ereditarietà multipla può divenire comunque complesso e poco chiaro (sia per il programmatore che per limplementatore) 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 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

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


Scaricare ppt "Ereditarietà multipla C++ method vs Twin-Objects Daniela Briola Orlin Velinov."

Presentazioni simili


Annunci Google