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

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

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

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

Ereditarietà Ereditarietà multiplamultipla

C++ method vs Twin-ObjectsC++ method vs Twin-ObjectsDaniela BriolaDaniela Briola

Orlin VelinovOrlin Velinov

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

Ereditarietà singolaEreditarietà singola

Ogni linguaggio Object Oriented Ogni linguaggio Object Oriented supporta il concetto di supporta il concetto di ereditarietàereditarietà

Si dice che una classe è Si dice che una classe è derivataderivata da un’altra quando ne estende le da un’altra quando ne estende le funzionalità grazie all’funzionalità grazie all’inheritanceinheritance

A

BA Nell’esempio la classe B è derivata Nell’esempio la classe B è derivata

dalla classe A.dalla classe A.

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

Ereditarietà multiplaEreditarietà multipla

Permette di comporre classi derivando Permette di comporre classi derivando da più classi base.da più classi base.

A B

CA B

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

Ereditarietà multiplaEreditarietà multipla

Possibilità di comporre Possibilità di comporre velocemente oggetti velocemente oggetti molto complessimolto complessi

Complicazione notevole Complicazione notevole del linguaggio che la del linguaggio che la implementaimplementa

Aggregare funzionalità Aggregare funzionalità differenti in un’unica differenti in un’unica classeclasse

Soluzione elegante e di Soluzione elegante e di grande utilitàgrande utilità

Scarsa efficienza anche Scarsa efficienza anche quando non viene usataquando non viene usata

Rischio elevato di Rischio elevato di “name clash”“name clash”

VantaggiVantaggi Svantaggi Svantaggi

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

Ereditarietà multipla:Ereditarietà multipla:il problema del diamanteil problema del diamante Se una classe eredita membri con lo Se una classe eredita membri con lo

stesso nome da più di un genitore, stesso nome da più di un genitore, avviene un conflittoavviene un conflitto

A

B1 B2

C

Ci sono due strategie possibili:Ci sono due strategie possibili:

gestire direttamente il grafo di gestire direttamente il grafo di ereditarietàereditarietà

trasformarlo in una catena lineare trasformarlo in una catena lineare (ereditarietà singola)(ereditarietà singola)

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

Ereditarietà multipla:Ereditarietà multipla:il problema del diamanteil problema del diamante

La semantica dei linguaggi orientati La semantica dei linguaggi orientati al grafo modella direttamente al grafo modella direttamente l’albero di derivazionel’albero di derivazione

Se un membro è definito solo dalla Se un membro è definito solo dalla classe A, è ereditato da B1 e da C classe A, è ereditato da B1 e da C senza errorisenza errori

Si deve prevedere il caso di Si deve prevedere il caso di ridefinizione dei metodi doppi da ridefinizione dei metodi doppi da parte di B2parte di B2

A

B1 B2

C

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

Ereditarietà multipla:Ereditarietà multipla:il problema del diamanteil problema del diamante

Soluzione LineareSoluzione Lineare:: La gerarchia di derivazione viene linearizzataLa gerarchia di derivazione viene linearizzata Si elimina l’invocazione multipla di metodi Si elimina l’invocazione multipla di metodi

della soluzione precedentedella soluzione precedente SvantaggiSvantaggi

Lo sviluppatore non è al corrente della Lo sviluppatore non è al corrente della gerarchia di sottotipazione implicitagerarchia di sottotipazione implicita

La selezione del metodo da utilizzare è a La selezione del metodo da utilizzare è a discrezione del compilatorediscrezione del compilatore

Problemi nel collegamento con il genitore Problemi nel collegamento con il genitore effettivoeffettivo

A

B2

B1

C

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

Ereditarietà multiplaEreditarietà multipla

Implementazione C++Implementazione C++

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

C++ Ereditarietà singolaC++ Ereditarietà singola

In C++ una In C++ una oggetto oggetto è una regione di memoria contiguaè una regione di memoria contigua

int aint a

class A {class A { int a;int a; void f(int i);void f(int i);};};

Nell’area di memoria riservata all’oggetto Nell’area di memoria riservata all’oggetto papa viene solo salvato un intero viene solo salvato un intero La funzione La funzione ff, essendo non-virtual (statica), è definita esternamente all’oggetto , essendo non-virtual (statica), è definita esternamente all’oggetto papa, quindi è come fosse una funzione/procedura normale., quindi è come fosse una funzione/procedura normale.

A* pa;A* pa;pa->f(2);pa->f(2);

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

int cint c

C++ Ereditarietà singolaC++ Ereditarietà singola

Gli oggetti composti (derivati) sono costruiti dal Gli oggetti composti (derivati) sono costruiti dal compilatore concatenando le aree di memoria.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 bint b

int aint a

Se la classe definisce metodi Se la classe definisce metodi virtualvirtual entra in gioco la tabella delle funzioni entra in gioco la tabella delle funzioni (VMT): (VMT): ogni oggetto ha un puntatore alla VMT, che permette di identificare ogni oggetto ha un puntatore alla VMT, che permette di identificare la funzione effettivamente da usare.la funzione effettivamente da usare.

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

C++ PC++ Polimorfismoolimorfismo

Consente che gli oggetti assumano comportamenti Consente che gli oggetti assumano comportamenti differenti a seconda del contesto in cui operanodifferenti a seconda del contesto in cui operano

In particolare se In particolare se PtrPtr è un puntatore di tipo è un puntatore di tipo TT, allora , allora PtrPtr può puntarepuò puntare non solo a istanze di tipo non solo a istanze di tipo TT ma anche ma anche a a istanze di classi derivate da istanze di classi derivate da TT

T* Ptr = 0; // Puntatore nullo

/* ... */

Ptr = new Td; // Td è una classe derivata da T

Il polimorfismo è un concetto fondamentale della Il polimorfismo è un concetto fondamentale della programmazione OOprogrammazione OO

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

C++ PC++ Polimorfismo (2)olimorfismo (2)

C++ fa in modo che il corretto tipo dell’oggetto venga C++ fa in modo che il corretto tipo dell’oggetto venga determinato automaticamente alla chiamata della determinato automaticamente alla chiamata della funzionefunzione

In questo modo il linking della funzione viene rimandato In questo modo il linking della funzione viene rimandato a runtimea runtime (binding dinamico) (binding dinamico)

Per fare ciò bisogna dichiarare la funzione membro Per fare ciò bisogna dichiarare la funzione membro virtualvirtual

class T {class T {

public: virtual void Paint();public: virtual void Paint();

};};

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

C++ PC++ Polimorfismo:olimorfismo:ImplementazioneImplementazione

1.1. I metodi virtuali vengono ereditati allo stesso I metodi virtuali vengono ereditati allo stesso modo di quelli non virtualmodo di quelli non virtual, possono anch'essi essere , possono anch'essi essere sottoposti a overloading ed essere ridefinitisottoposti a overloading ed essere ridefiniti

2.2. non c'e` alcuna differenza eccetto chenon c'e` alcuna differenza eccetto che una loro una loro invocazione viene risolta a run-timeinvocazione viene risolta a run-time

3.3. In una classe con un metodo virtuale, In una classe con un metodo virtuale, il compilatore il compilatore associa alla classeassocia alla classe (non all'istanza) (non all'istanza) una tabella una tabella (VMT)(VMT) che contiene per ogni metodo virtuale l'indirizzo che contiene per ogni metodo virtuale l'indirizzo alla corrispondente funzionealla corrispondente funzione

4.4. Ogni istanza di quella classe conterrà poi al suo Ogni istanza di quella classe conterrà poi al suo interno un puntatore (VPTR) alla VMTinterno un puntatore (VPTR) alla VMT

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

C++ PC++ Polimorfismo:olimorfismo:OverheadOverhead

L'invocazione di un metodo virtuale e` piu` costosa di L'invocazione di un metodo virtuale e` piu` costosa di quella per una funzione membro ordinaria, tuttavia il quella per una funzione membro ordinaria, tuttavia il compilatore puo` evitare tale overhead risolvendo a compilatore puo` evitare tale overhead risolvendo a compile-time tutte quelle situazioni in cui il tipo e` compile-time tutte quelle situazioni in cui il tipo e` effettivamente noto effettivamente noto

Td Obj1;Td Obj1; T* Ptr = 0;T* Ptr = 0;

Obj1.Paint(); // Chiamata risolvibile staticamenteObj1.Paint(); // Chiamata risolvibile staticamente Ptr->Paint(); // Questa invece noPtr->Paint(); // Questa invece no

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

Polimorfismo Polimorfismo nell’ereditarietà multiplanell’ereditarietà multipla

class A { virtual void f(); };class A { virtual void f(); };class B { virtual void f(); virtual void g() };class B { virtual void f(); virtual void g() };class C: A, B { void f(); };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 C eredita sia da A che da B, dunque l’assegnazione B, dunque l’assegnazione è correttaè corretta

Tutte tre le chiamate Tutte tre le chiamate invocano C::f()invocano C::f()

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

C++ Classi astratteC++ Classi astratte

Ereditarietà e polimorfismo possono essere combinati per Ereditarietà e polimorfismo possono essere combinati per realizzare classi il cui unico scopo è creare una interfaccia realizzare classi il cui unico scopo è creare una interfaccia comune a una gerarchia di classicomune 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 Funzioni virtuali purevirtuali pure

Una classe che possiede Una classe che possiede funzioni virtuali purefunzioni virtuali pure è detta è detta classe astratta e non è possibile istanziarlaclasse astratta e non è possibile istanziarla

Può essere utilizzata unicamente per derivare nuove Può essere utilizzata unicamente per derivare nuove classi forzandole a fornire determinati metodiclassi forzandole a fornire determinati metodi

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

AmbiguitàAmbiguitàAnalizziamo il caso in cui la Analizziamo il caso in cui la classe D derivi da B1 e B2classe D derivi da B1 e B2

class Base1 {class Base1 {

public:public:

void f();void f();

};};

class Base2 {class Base2 {

public:public:

void f();void f();

void f2();void f2();

};};

class Derived : Base1, Base2 {class Derived : Base1, Base2 {

// Non ridefinisce f()// Non ridefinisce f()

};};

B1 B2

DB1 B2

La classe La classe DerivedDerived eredita piu` eredita piu` volte gli stessi membri, in volte gli stessi membri, in particolare la funzione particolare la funzione f()f()

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

Ambiguità – soluzione esplicitaAmbiguità – soluzione esplicitaDerived x; Derived x; x.f()x.f() //Errore, è ambiguo! //Errore, è ambiguo!

N.B.: questo è un errore che appare solo a runtimeN.B.: questo è un errore che appare solo a runtime

Soluzione: Soluzione: Derived x; Derived x; x.B1::f()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ù non è necessario che la stessa definizione si trovi in più

classi basi dirette, è sufficiente che essa giunga alla classi basi dirette, è sufficiente che essa giunga alla

classe derivata attraverso due classi basi distinteclasse derivata attraverso due classi basi distinte il problema non si sarebbe posto se Derived avesse

ridefinito la funzione membro f().

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

C++ Ereditarietà multipla:C++ Ereditarietà multipla:Ambiguità - Ambiguità -

ImplementazioneImplementazione Come implementa il C++ una soluzione esplicita Come implementa il C++ una soluzione esplicita

attraverso qualificatore x.b1::f() ?attraverso qualificatore x.b1::f() ?

1.1. b1::f() si aspetta un puntatore b1* (che diventa il suo b1::f() si aspetta un puntatore b1* (che diventa il suo thisthis))

2.2. A runtime conosciamo però solo il puntatore della classe A runtime conosciamo però solo il puntatore della classe derivata “derived”derivata “derived”

3.3. Il compilatore aggiunge un opportuno Il compilatore aggiunge un opportuno deltadelta (memorizzato nella VMT) (memorizzato nella VMT) per raggiungere la parte per raggiungere la parte relativa a B1 in “derived”relativa a B1 in “derived”

4.4. In pratica, il compilatore trasforma una chiamata diretta in In pratica, il compilatore trasforma una chiamata diretta in una indiretta, sommando un offsetuna indiretta, sommando un offset

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

C++ Ereditarietà multipla:C++ Ereditarietà multipla:ImplementazioneImplementazione

C::f()C::f()

C::f()C::f()

B2::g()B2::g()

00

00

-delta(B2)-delta(B2)

Parte B1Parte B1

Parte B2Parte B2

Parte DParte D

Delta(B2)

VMT

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

AmbiguitàAmbiguità IIl problema dell'ambiguità può essere portato al caso l problema dell'ambiguità può essere portato al caso

estremo in cui una classe erediti più volte una stessa estremo in cui una classe erediti più volte una stessa classe baseclasse base

class Base { };class Base { };

class Derived1 : Base { };class Derived1 : Base { };

class Derived2 : Base { };class Derived2 : Base { };

class Derived3 : Derived1, Derived2 { };class Derived3 : Derived1, Derived2 { };

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

AmbiguitàAmbiguitàDerived3

Derived1 Derived2

Base Base

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

C++ Ereditarietà multipla:C++ Ereditarietà multipla:Ambiguità – ereditarietà Ambiguità – ereditarietà

virtualevirtuale Il C++ permette di risolvere il problema molto Il C++ permette di risolvere il problema molto

elegantemente con l’uso di elegantemente con l’uso di classi base virtualiclassi base virtuali

class Base { }; class Base { };

class Derived1 : class Derived1 : virtualvirtual Base { }; Base { };

class Derived2 : class Derived2 : virtualvirtual Base { }; Base { };

class Derived3 : Derived1, Derived2 { };class Derived3 : Derived1, Derived2 { };

Quando una classe eredita tramite la keyword Quando una classe eredita tramite la keyword virtualvirtual il il compilatore compilatore non copia il contenuto della classe base non copia il contenuto della classe base nella classe derivatanella classe derivata, ma , ma inserisce nella classe derivata inserisce nella classe derivata un puntatore ad un’unica istanza della classe base un puntatore ad un’unica istanza della classe base

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

C++ Ereditarietà multipla:C++ Ereditarietà multipla:Ambiguità – ereditarietà Ambiguità – ereditarietà

virtualevirtuale

Derived3

Derived1

Derived2

virtual

Base

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

Ambiguità – ridefinizioneAmbiguità – ridefinizione In alcuni casi l’ambiguità persiste. Supponiamo che una delle In alcuni casi l’ambiguità persiste. Supponiamo che una delle

classi intermedie ridefinisca una funzione membro della classi intermedie ridefinisca una funzione membro della classe base.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!

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

Ambiguità – ridefinizioneAmbiguità – ridefinizione La situazione è diversa se La situazione è diversa se solo una delle classi intermedie solo una delle classi intermedie

fa la ridefinizionefa la ridefinizioneclass 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!

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

class A : virtual L {...};

class B : virtual L {...};

class C : A , B {...};

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

Ambiguità – EsempioAmbiguità – EsempioLa “virtualità” di una classe non è una sua caratteristica, La “virtualità” di una classe non è una sua caratteristica, ma è data dall’essere dichiarata come tale nelle classi ma è data dall’essere dichiarata come tale nelle classi che la ereditano. Vediamo un esempio:che la ereditano. Vediamo un esempio:

In questo caso la In questo caso la classe C avrà un solo classe C avrà un solo riferimento ad un riferimento ad un oggetto di classe Loggetto di classe L

class D : L,C{...};In questo caso invece la In questo caso invece la classe D avrà due “sotto-classe D avrà due “sotto-oggetti” di tipo L, un virtuale oggetti” di tipo L, un virtuale e uno normalee uno normale

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

i costruttorii costruttori Le classi derivate normalmente chiamano Le classi derivate normalmente chiamano

implicitamente (o esplicitamente) i costruttori delle implicitamente (o esplicitamente) i costruttori delle classi baseclassi base

In caso di ereditarietà multipla con classe base virtuale In caso di ereditarietà multipla con classe base virtuale si pone il problema di decidere chi inizializza la classe si pone il problema di decidere chi inizializza la classe base (in quale ordine)base (in quale ordine)

In C++ le classi virtual sono inizializzate dalle classi In C++ le classi virtual sono inizializzate dalle classi massimamente derivatemassimamente derivate

In generale i costruttori sono eseguiti nell’ordine in cui In generale i costruttori sono eseguiti nell’ordine in cui compaiono nella dichiarazione eccetto quelli delle classi compaiono nella dichiarazione eccetto quelli delle classi virtual, eseguiti primavirtual, eseguiti prima

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

i distruttorii distruttori Stesso discorso per i distruttori, ma in ordine Stesso discorso per i distruttori, ma in ordine

contrariocontrario

Il compilatore C++ si preoccupa di Il compilatore C++ si preoccupa di distruggere le classi virtual una sola voltadistruggere le classi virtual una sola volta , , anche se vengono ereditate molteplici volteanche se vengono ereditate molteplici volte

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

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

Problemi di efficienzaProblemi di efficienzaL’ereditarietà multipla comporta alcuni costi in termini di L’ereditarietà multipla comporta alcuni costi in termini di

efficienza:efficienza:1.1.Sottrazione di una costante per ogni accesso ai membri Sottrazione di una costante per ogni accesso ai membri

delle classi basedelle classi base2.2.Un word per funzione in ogni VMT (per il delta)Un word per funzione in ogni VMT (per il delta)3.3.Un riferimento in memoria ed una sottrazione per ogni Un riferimento in memoria ed una sottrazione per ogni

chiamata a funzione virtualechiamata a funzione virtuale4.4.Un riferimento in memoria ed una sottrazione per ogni Un riferimento in memoria ed una sottrazione per ogni

accesso ai membri di una classe base virtualeaccesso ai membri di una classe base virtuale

La 1 e la 4 sono penalizzanti solo se l’ereditarietà multipla è La 1 e la 4 sono penalizzanti solo se l’ereditarietà multipla è effettivamente usata. La 2 e la 3 sempreeffettivamente usata. La 2 e la 3 sempre

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

Il metodo qui presentato offre due modalità di estendere il Il metodo qui presentato offre due modalità di estendere il “name space” di una classe:“name space” di una classe:

classe baseclasse base classe base virtualeclasse base virtuale

Comunque, le regole per gestire questi due tipi di classi Comunque, le regole per gestire questi due tipi di classi sono indipendenti dal tipo di classe effettivamente usata, sono indipendenti dal tipo di classe effettivamente usata, inoltre:inoltre:

le ambiguità sono illegalile ambiguità sono illegali le regole per la gestione dei vari membri sono le stesse che le regole per la gestione dei vari membri sono le stesse che

con ereditarietà singolacon ereditarietà singola le regole di visibilità ed inizializzazione sono le stesse le regole di visibilità ed inizializzazione sono le stesse

dell’ereditarietà singoladell’ereditarietà singola Violazioni di queste regole sono segnalate a compile-timeViolazioni di queste regole sono segnalate a compile-time

C++ Ereditarietà C++ Ereditarietà multipla:multipla:

ConsiderazioniConsiderazioni

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

C++ Ereditarietà multipla:C++ Ereditarietà multipla:ConclusioniConclusioni

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à

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

Ereditarietà multiplaEreditarietà multipla

Implementazione modelloImplementazione modello“Twin Objects”“Twin Objects”

(J.Templ)(J.Templ)

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

Twin ObjectsTwin Objects

Sono un modo di realizzare l’ereditarietà multipla Sono un modo di realizzare l’ereditarietà multipla usando l’ereditarietà singolausando l’ereditarietà singola

Possono essere usati per implementare l’ereditarietà Possono essere usati per implementare l’ereditarietà multipla in linguaggi che non la supportano, ad multipla in linguaggi che non la supportano, ad esempio in Javaesempio in Java

Aiutano a risolvere problemi tipici dell’ereditarietà Aiutano a risolvere problemi tipici dell’ereditarietà multipla quali l’ambiguità dei nomimultipla quali l’ambiguità dei nomi

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

Twin Objects - modelloTwin Objects - modello

CA e CB sono chiamati twins (gemelli)CA e CB sono chiamati twins (gemelli) Sono sempre generati assieme e legati dai Sono sempre generati assieme e legati dai

puntatori T1 e T2puntatori T1 e T2

Multiple InheritanceMultiple Inheritance Twin objectsTwin objects

A BB

C

A BB

CBCBCACA

CCT1T1

T2T2

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

Twin Objects - modelloTwin Objects - modello

A BB

CBCB

CACA

EE

CECE

Se la classe C eredita da Se la classe C eredita da nn classi base, ci saranno classi base, ci saranno nn twins da gestiretwins da gestire

CC

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

Twin Objects - modelloTwin Objects - modello

Se dobbiamo inserire nella nostra classe attributi o metodi Se dobbiamo inserire nella nostra classe attributi o metodi aggiuntivi (non definiti nelle classi basi) abbiamo due metodi:aggiuntivi (non definiti nelle classi basi) abbiamo due metodi:

P1 P2P2

C2C2CCT1T1

T2T2

li mettiamo in uno dei due li mettiamo in uno dei due twin twin (ad es. in C1, che (ad es. in C1, che chiamiamo C); questo è chiamiamo C); questo è l’approccio seguito l’approccio seguito normalmentenormalmente

creiamo una classe creiamo una classe aggiuntiva C in cui li aggiuntiva C in cui li inseriamoinseriamo

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

Twin Objects - Twin Objects - ereditarietàereditarietà

P1 P2P2

C2C2CCT1T1

T2T2

D2D2D1D1T1T1

T2T2

C2C2

P1 P2P2

CCT1T1

T2T2

DDNo

D non eredita da C2!D non eredita da C2!

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

Twin Objects - Twin Objects - CollaborazioneCollaborazione

Ogni classe figlio è responsabile per la comunicazione Ogni classe figlio è responsabile per la comunicazione con il suo padre e si occupa di inoltrare i messaggi alle con il suo padre e si occupa di inoltrare i messaggi alle classi gemelleclassi gemelle

I client referenziano uno dei figli direttamente, e tutti gli I client referenziano uno dei figli direttamente, e tutti gli altri tramite i puntatori a twin (la ‘T’ negli esempi)altri tramite i puntatori a twin (la ‘T’ negli esempi)

I client che necessitano di comunicare con uno dei I client che necessitano di comunicare con uno dei Padri, lo fanno attraverso la rispettiva classe-figlioPadri, lo fanno attraverso la rispettiva classe-figlio

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

Twin Objects - Twin Objects - ImplemenazioneImplemenazione

AstrazioneAstrazione: le classi gemelle devono cooperare : le classi gemelle devono cooperare strettamente tra loro, permettendo di accedere ai loro strettamente tra loro, permettendo di accedere ai loro membri privati (visibilità package in Java). Il tutto deve membri privati (visibilità package in Java). Il tutto deve apparire come un unico oggetto dall’esterno.apparire come un unico oggetto dall’esterno.

EfficienzaEfficienza: l’uso di twin objects sostituisce le relazioni : l’uso di twin objects sostituisce le relazioni per ereditarietà con relazioni per composizione. Ciò per ereditarietà con relazioni per composizione. Ciò comporta la necessità di inoltrare messaggi e quindi comporta la necessità di inoltrare messaggi e quindi minore efficienza, ma poiché l’ereditarietà multipla è in minore efficienza, ma poiché l’ereditarietà multipla è in genere più lenta, non si notano differenze sostanziali.genere più lenta, non si notano differenze sostanziali.

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

Raggruppare i Twin in un unico blocco contiguo per Raggruppare i Twin in un unico blocco contiguo per velocizzare l’allocazione dell’oggetto che li velocizzare l’allocazione dell’oggetto che li usausanecessità di utilizzare puntatori nel blocco per necessità di utilizzare puntatori nel blocco per collegare i twincollegare i twin

Twin Objects - Twin Objects - OttimizzazioniOttimizzazioni

sostituire il puntatore con un offset relativo all’inizio sostituire il puntatore con un offset relativo all’inizio del twindel twin

se l’allocazione degli oggetti client e dei twin è resa se l’allocazione degli oggetti client e dei twin è resa uguale per ogni istanza, l’offset è una costante uguale per ogni istanza, l’offset è una costante memorizzabile a partememorizzabile a parte

le VMT possono essere memorizzate le VMT possono essere memorizzate contiguamente in un bloccocontiguamente in un blocco

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

Twin Objects - EsempioTwin Objects - Esempio

Java non consente l’ereditarietà multiplaJava non consente l’ereditarietà multipla, tuttavia in , tuttavia in alcuni casi serve poter mettere assieme oggetti di alcuni casi serve poter mettere assieme oggetti di natura diversa, ad esempio implementando applet che natura diversa, ad esempio implementando applet che reagiscono alle azioni del mousereagiscono alle azioni del mouse

Costruendo un Costruendo un appletapplet, serve poter ereditare da un , serve poter ereditare da un generico generico AppletApplet a cui verrà ridefinito il metodo a cui verrà ridefinito il metodo .Paint().Paint() e da una classe e da una classe StdMouseListenerStdMouseListener di cui verranno di cui verranno ridefiniti i metodi ridefiniti i metodi mousePressed(), mouseClicked() mousePressed(), mouseClicked() ee mouseReleased()mouseReleased()

Lo schema che segue riassume la struttura del nostro Lo schema che segue riassume la struttura del nostro oggetto composto MyApplet + MyAppletListeneroggetto composto MyApplet + MyAppletListener

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

Twin Objects – EsempioTwin Objects – Esempio

Applet

resize()paint()…

StdMouseListenerStdMouseListener

mousePressed()mouseClicked()mouseReleased()

paint()paint()CC T1T1

T2T2

MyAppletMyApplet

mousePressed()mouseClicked()mouseReleased()

MyAppletListenerMyAppletListener

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

Twin Objects - EsempioTwin Objects - Esempio

class Applet {class Applet {

public void paint();public void paint();

public void resize();public void resize();

……

}}

class StdMouseListener {class StdMouseListener {public void mousePressed();public void mousePressed();public void mouseClicked();public void mouseClicked();public void mouseReleased();public void mouseReleased();……

}} Queste sono le definizioni delle due classi base di cui desideriamo Queste sono le definizioni delle due classi base di cui desideriamo

fare ereditarietà multipla attraverso l’uso del modello Twin Objectsfare ereditarietà multipla attraverso l’uso del modello Twin Objects

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

Twin Objects - EsempioTwin Objects - Esempio

class MyApplet extends Applet {class MyApplet extends Applet {

MyAppletListener listener; /* il Twin */MyAppletListener listener; /* il Twin */

public void paint() { /* ridefinisco */ }public void paint() { /* ridefinisco */ }

……

}}class MyAppletListener extends StdMouseListener {class MyAppletListener extends StdMouseListener {

MyApplet applet; /* il Twin */MyApplet applet; /* il Twin */public void mousePressed () { /* ridefinisco */ }public void mousePressed () { /* ridefinisco */ }public void mouseClicked () { /* ridefinisco */ }public void mouseClicked () { /* ridefinisco */ }public void mouseReleased () { /* ridefinisco */ }public void mouseReleased () { /* ridefinisco */ }……

}} Ogni “twin” eredita il proprio parent ridefinendone i metodi Ogni “twin” eredita il proprio parent ridefinendone i metodi

opportuni e si occupa di comunicare con il proprio fratello.opportuni e si occupa di comunicare con il proprio fratello.

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

Twin Objects - EsempioTwin Objects - Esempio

Layout in memoria:Layout in memoria:

MyAppletMyApplet

AppletApplet

MyStdMouseListenerMyStdMouseListener

StdMouseListenerStdMouseListener

twinstwins

Come evidente, si tratta di oggetti completamente separati a livello di Come evidente, si tratta di oggetti completamente separati a livello di memoria. Il link tra le classi è fatto a livello di applicazione.memoria. Il link tra le classi è fatto a livello di applicazione.

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

C++ - Contro esempioC++ - Contro esempio

class Applet {class Applet {virtual void paint();virtual void paint();virtual void resize();virtual void resize();……

}}class StdMouseListener {class StdMouseListener {

virtual void mousePressed();virtual void mousePressed();virtual void mouseClicked();virtual void mouseClicked();virtual void mouseReleased();virtual void mouseReleased();……

}} Come per l’esempio Twin Objects, abbiamo due classi base iniziali Come per l’esempio Twin Objects, abbiamo due classi base iniziali

da cui vogliamo fare ereditarietà multipla...da cui vogliamo fare ereditarietà multipla... ““virtualvirtual” indica che le funzioni sono di tipo latebinding (come ” indica che le funzioni sono di tipo latebinding (come

nell’es. Java) e non statiche.nell’es. Java) e non statiche.

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

C++ - Contro esempioC++ - Contro esempio

class MyApplet : Applet, StdMouseListener {class MyApplet : Applet, StdMouseListener {

void paint() { /* ridefinisco */ }void paint() { /* ridefinisco */ }

void mousePressed() { /* ridefinisco */ }void mousePressed() { /* ridefinisco */ }

void mouseClicked() { /* ridefinisco */ }void mouseClicked() { /* ridefinisco */ }

void mouseReleased() { /* ridefinisco */ }void mouseReleased() { /* ridefinisco */ }

……

}} Il C++ ci consente di avere un’unica classe MyApplett che Il C++ ci consente di avere un’unica classe MyApplett che

eredita contemporaneamente da Applet e StdMouseListener.eredita contemporaneamente da Applet e StdMouseListener. Ridefinisco i metodi secondo le esigenze; per fortuna non ci sono Ridefinisco i metodi secondo le esigenze; per fortuna non ci sono

name clashes quindi non ci preoccupiamo di usare qualificatori name clashes quindi non ci preoccupiamo di usare qualificatori esplicitiespliciti

A livello implementativo, il compilatore traduce una chiamata del A livello implementativo, il compilatore traduce una chiamata del tipo *obj->paint() in una chiamata indiretta sommando un delta tipo *obj->paint() in una chiamata indiretta sommando un delta riferito alla classe parent e memorizzato nella VMTriferito alla classe parent e memorizzato nella VMT

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

C++ contro esempioC++ contro esempio

Myapp::paint()Myapp::paint()

Myapp::paint()Myapp::paint()

00

-delta(StdML)-delta(StdML)

Parte Parte AppletApplet

Parte Parte StdmouseStdmouselistenerlistener

Parte Parte MyappletMyapplet

metodi ridefiniti da metodi ridefiniti da MyAppletMyApplet

VMTVMT

delta(StdML)delta(StdML)

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

L’implementazione dell’ereditarietà multipla del C+L’implementazione dell’ereditarietà multipla del C++ porta ad un overhead anche dell’ereditarietà + porta ad un overhead anche dell’ereditarietà singolasingola

Il codice deve essere riaggiustato per cambiare il Il codice deve essere riaggiustato per cambiare il “self”“self”

L’ereditarietà multipla in se stessa non è né molto L’ereditarietà multipla in se stessa non è né molto utile né veramente necessaria dal momento che utile né veramente necessaria dal momento che può essere facilmente simulatapuò essere facilmente simulata

Il vantaggio che offre è puramente sintatticoIl vantaggio che offre è puramente sintattico Il suo costo non è giustificato dalle opportunità che Il suo costo non è giustificato dalle opportunità che

offreoffre

Considerazioni di Templ Considerazioni di Templ sull’ereditarietà multiplasull’ereditarietà multipla

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

ConclusioniConclusioni L’ereditarietà multipla è uno strumento potente che L’ereditarietà multipla è uno strumento potente che

consente di affrontare problemi complessi con eleganzaconsente di affrontare problemi complessi con eleganza La sua implementazione nativa può generare un lieve La sua implementazione nativa può generare un lieve

decadimento del performances anche quando non viene decadimento del performances anche quando non viene usatausata (vedi C++) (vedi C++)

Gestire un linguaggio con ereditarietà multipla può Gestire un linguaggio con ereditarietà multipla può divenire comunque complesso e poco chiaro (sia per il divenire comunque complesso e poco chiaro (sia per il programmatore che per l’implementatore)programmatore che per l’implementatore)

I linguaggi moderni tendono ad evitarla (es. Java), I linguaggi moderni tendono ad evitarla (es. Java), adoperando tecniche altrettanto efficaci come i Twin adoperando tecniche altrettanto efficaci come i Twin Objects, Objects, senza overhead e complicazioni, dal momento senza overhead e complicazioni, dal momento che i vantaggi, sebbene ci siano, forse non giustificano che i vantaggi, sebbene ci siano, forse non giustificano le necessarie modifiche dei linguaggi OO già esistentile necessarie modifiche dei linguaggi OO già esistenti

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

RiferimentiRiferimenti

““Twin – A Design Pattern for Modeling Multiple Twin – A Design Pattern for Modeling Multiple Inheritance”Inheritance” J. J. TemplTempl

““Multiple Inheritance for C++” Multiple Inheritance for C++” Bjarne StroustrupBjarne Stroustrup

Manuale del C++Manuale del C++ Bjarne Stroustrup Bjarne Stroustrup