Ereditarietà e polimorfismo -...

35
Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/2009 1 Corso di Programmazione ad oggetti Ereditarietà e polimorfismo a.a. 2008/2009 Claudio De Stefano

Transcript of Ereditarietà e polimorfismo -...

Page 1: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20091

Corso di Programmazione ad oggetti

Ereditarietà e polimorfismo

a.a. 2008/2009Claudio De Stefano

Page 2: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20092

Costruttori, distruttori ed ereditarietà

■ Quando si usa l'ereditarietà bisogna tenere conto dei costruttori e distruttori. Èinfatti possibile che una classe base, una classe derivata o entrambe contengano una funzione costruttore e/o distruttore

■ Vi sono due problemi principali derivanti dall'uso di costruttori e distruttori quando si usa l'ereditarietà.

– In quale momento vengono chiamate le funzioni costruttore e distruttore della classe base e di quella derivata?

– Come fare per passare per passare parametri alle funzioni costruttore della classe base?

■ In generale quando si crea un oggetto di una classe derivata si chiama prima il costruttore della classe base e poi quello della classe derivata.

■ Per quanto riguarda la distruzione. Accade l'inverso: viene prima chiamato il distruttore della classe derivata e poi quello della classe base.

Page 3: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20093

Costruttori, distruttori ed ereditarietà: esempio

class Base { public:Base(){cout<<”costruzione di base”;<<endl};~Base(){cout<<”distruzione di base”;<<endl};

};

class Derived { public:Derived(){cout<<”costruzione di derived”<<endl;};~Derived(){cout<<”distruzione di derived”<<endl;};

};

costruzione di basecostruzione di deriveddistruzione di basedistruzione di derived

OUTPUT#include derived.h

main(){

Derived d;

};

Page 4: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20094

Costruttori, distruttori ed ereditarietà

■ Il risultato dell'esempio precedente può essere generalizzato dicendo che i costruttori sono eseguiti seguendo l'ordine di derivazione, mentre i distruttori sono eseguiti in ordine inverso rispetto a quello di derivazione.

■ Se si riflette un attimo, questa scelta è praticamente obbligata. Infatti è possibile che il costruttore della classe derivata usi alcuni dei membri inizializzati dal costruttore della classe base. E si aspetta che tali valori siano stati precedentemente iniziliazzati come previsto dal costruttore della classe base.

■ Per quanto riguarda i distruttori la motivazione è la stessa, il distruttore della classe derivata potrebbe tentare di accedere ad un'estensione della classe base che viene distrutta dal distruttore della classe base.

Page 5: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20095

Passaggio di argomenti a costruttori di classe base

■ La forma generale di dichiarazione estesa di un costruttore di una classe derivata è la seguente:

costruttore_derivata(elenco-argomenti): base1(elenco-argomenti),

base2(elenco-argomenti),...baseN(elenco-argomenti){// Corpo del costruttore derivato

.

.

.

}

Page 6: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20096

Gerarchie di classi

Derived1

Base

Derived2

■ Derived1 e Derived2 sono specificazioni diverse di Base (ad esempio Derived1 e Derived2 aggiungono servizi diversi).

■ Diritti di accesso:– Variabili membro: in Base sono protette, in Derived1 e Derived2 sono private;– Funzioni membro: sono pubbliche;– Modalità di derivazione: pubblica

Page 7: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20097

Gerarchie di classi

Base

Derived1

Derived2

■ Derived1 e Derived2 sono successive specificazioni di Base (per “raffinamento”).

■ Diritti di accesso:– Variabili membro: in A e in B sono protette, in C sono private– Funzioni membro: sono pubbliche– Modalità di derivazione: pubblica

Page 8: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20098

I puntatori a tipi derivati

■ In generale, un puntatore di un dato tipo non può puntare ad un oggetto di un tipo diverso.

■ Vi è pero un'importante eccezione a questa regola che riguarda le classi derivate. Poniamo di avere le classi B e D, con D che deriva da B. In questa situazione, un putatore di tipo B* può anche puntare ad un oggetto di tipo D.

■ Possiamo generalizzare la situazione precedente dicendo che: un puntatore ad una classe può anche essere utilizzato come puntatore ad un oggetto di una qualsiasi delle classi derivate da tale classe base.

■ La regola inversa NON vale: un puntatore ad una classe derivata non può puntare ad oggetti della classe base.

■ Inoltre, puntando ad un oggetto della classe derivata con un puntatore alla classe base è possibile accedere SOLO ai membri della classe base che sono stati importati dalla classe base.

Page 9: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/20099

Puntatori a tipi derivati: esempio

class Base {protected:int i;

public:void set_i(int a) {i=a;}int get_i() {return i;};

};

class Derived : public Base {int j;

public: void set_j(int a) {i=a;}int get_j() {return i;};

};

#include derived.h

main(){

Base *bp;Derived d;

bp = &d; // OK bp->set_i(10); // OKcout<<endl<<bp->get_i(); // OK

bp->set_j(1); // ERRORE!cout<<endl<<bp->get_j(); // ERRORE!

};

Bp è dichiarato come puntatore alla classe Base, la quale non contiene le funzioni set_j e get_j.Pertanto il compilatore segnala un errore

Page 10: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200910

I puntatori a tipi derivati: accesso mediante casting

■ Per risolvere la situazione vista alla slide precedente si può usare una conversione di tipo mediante casting:

#include derived.h

main(){

Base *bp;Derived d;

bp = &d; ...

((derived *)bp)->set_j(1); // OK cout<<endl<<((derived *)bp)->get_j(); // OK

};

Page 11: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200911

I puntatori a tipi derivati: aritmetica dei puntatori

■ È importante ricordare che l'aritmetica dei puntatori fa riferimento al puntatore base. Per questo motivo, quando un puntatore base punta ad un oggetto derivato, l'incremento del puntatore non fa in modo che questo punti all'oggetto successivo, del tipo derivato. Al contrario esso punterà a quello che dovrebbe essere l'oggetto successivo del tipo base.

■ Il seguente programma viene compilato, ma è semanticamente sbagliato#include derived.h

main(){

Base *bp; Derived d[2];

bp = d;d[0].set_i(1);d[1].set_i(2); .

cout<<endl<<bp->get_i(); bp++;

cout<<endl<<bp->get_i(); };

Equivale a bp = bp+ sizeof(Base)

Visualizza un valore casuale

Page 12: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200912

Il Polimorfismo

Page 13: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200913

Il polimorfismo

POLIMORFISMO

“un interfaccia, più metodi”

Page 14: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200914

Il polimorfismo

■ Il meccanismo del polimorfismo consente ad un'interfaccia di controllare l'accesso ad una classe generale di azioni. La specifica azione sarà selezionata in base alla particolare situazione in atto.

■ L'utilizzazione di un'unica interfaccia aiuta a ridurre la complessità dei programmi.

■ Sarà compito del compilatore automatizzare la selezione dell'azione specifica (ovvero il metodo), da applicare ad una specifica situazione.

■ Il polimorfismo è supportato dal C++ sia al momento della compilazione (compile-time) che a tempo di esecuzione (run-time).

Page 15: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200915

Il polimorfismo: esempio

■ Un programma potrebbe definire tre tipi diversi di stack: uno per gli interi, uno per i caratteri e uno per i float.

■ Grazie al polimorfismo sarà possibile usare un solo insieme di nomi (push, pop, ecc.) per accedere alle funzioni specifiche dei tre tipi di stack definiti.

■ Ovviamente nel programma verranno implementate tre diverse funzioni per ogni specifica azione, ma il nome resterà lo stesso.

■ Sarà poi il compilatore a selezionare automaticamente il tipo di funzione corretta sulla base del tipo di stack utilizzato.

Page 16: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200916

Le funzioni virtuali

■ Il polimorfismo viene realizzato in C++ per mezzo delle funzioni virtuali.

■ Una funzione virtuale è una funzione membro dichiarata come virtual in una classe base e ridefinita in una classe derivata.

■ Quando si eredita una classe contenente una funzione virtuale, la classe derivata ridefinisce la funzione virtuale secondo le proprie esigenze.

■ Il compito principale della funzione virtuale definita nella classe base è quello di definire appunto al forma dell'interfaccia della funzione.

■ Le ridefinizioni nelle classe derivate, invece, implementa le specifiche azioni relative alle situazioni gestite dalla classe derivata stessa.

Page 17: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200917

Le funzioni virtuali

■ Quando si accede alle funzioni virtuali, per mezzo dell'operatore . (punto), tali funzioni si comportano come qualsiasi altra funzione membro.

■ La potenzialità delle funzioni virtuali, viene sfruttata quando si accede loro tramite puntatore(mediante l'operatore ->). Questo tipo di accesso consente di realizzare il polimorfismo run-time.

■ In precedenza abbiamo visto che i puntatori alla classe base possono puntare a qualsiasi classe derivata dalla base.

■ Quando un puntatore base punta ad un oggetto derivato che contiene una funzione virtuale, il C++ determina quale funzione chiamare sulla base del tipo di oggetto puntato. Questa determinazione viene eseguita run-time.

■ Pertanto, al variare del tipo di oggetto derivato puntato, cambia anche la versione della funzione virtuale che verrà eseguita.

Page 18: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200918

Le funzioni virtuali: esempio

class Base {public:virtual void show() { cout<<endl<<”oggetto della classe Base”;};

};

class Derived1 : public Base{public:void show() { cout<<endl<<”oggetto della classe Derived1”;};

};

class Derived2 : public Base{public:void show() { cout<<endl<<”oggetto della classe Derived2”;};

};

Page 19: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200919

Esempio di polimorfismo run-time#include derived.h

main(){

Base *bp, b; Derived1 d1; Derived1 d2; int choice;

cout<<endl<<”a quale oggetto vuoi visualizzare?”cout<<endl<<”0: Base”;cout<<endl<<”1: Derived1”;cout<<endl<<”2: Derived2”;

cin>>choice;

switch (choice) {case (0): bp = &b;

break; case (1): bp = &d1;

break;case (2): bp = &d1;

break; }

bp->show();

};

Page 20: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200920

Esempio di polimorfismo compile-time

#include derived.h

main(){

Base b; Derived1 d1; Derived1 d2; int choice;

cout<<endl<<”<quale oggetto vuoi visualizzare”cout<<endl<<”0: Base”;cout<<endl<<”1: Derived1”;cout<<endl<<”2: Derived2”;

cin>>choice;

switch (choice) {case (0): b.show();

break; case (1): d1.show();

break;case (2): d2.show();

break; }

};

Page 21: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200921

Differenze tra overloading di funzioni e funzioni virtuali

■ A prima vista, il meccanismo delle funzioni virtuali sembra simile a quello dell'overloading, ma di fatto si tratta di meccansimi totalmente diversi.

■ La principale differenza sta nel fatto che il prototipo di una funzione virtuale deve corrispondere esattamente a quello della classe base.

■ Nel caso dell'overloading delle funzioni, invece, il numero e il tipo di parametri deve modificare. Infatti è proprio questa differenza nel numero e nel tipo di parametri a guidare il compilatore nella determinazione della funzione giusta.

■ Un'altra importante differenza sta nel fatto che le funzioni costruttore, non possono essere virtuali.

Page 22: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200922

Ereditarietà dell'attributo virtual

■ Quando viene ereditata una funzione virtuale viene ereditata anche la sua natura virtuale.

■ Questo significa che quando una classe derivata che abbia ereditato una funzione virtuale viene a sua volta utilizzata come classe base per un ulteriore classe derivatal funzione resta virtuale.

class Base {public:virtual void show() { cout<<endl<<”oggetto della classe Base”;};

};

class Derived1 : public Base{public:void show() { cout<<endl<<”oggetto della classe Derived1”;};

};

class Derived2 : public Derived1{public:void show() { cout<<endl<<”oggetto della classe Derived2”;};

};

Page 23: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200923

Le funzioni virtuali gerarchiche

■ È importante osservare che non è obbligatorio ridefinire una funzione virtuale.

■ Infatti, se una classe derivata non ridefinisce una funzione virtuale, quando un oggetto della classe derivata tenterà di accedere a tale funzione, verrà utilizzata la funzione definita nella classe base.

■ La regola generale è che quando una classe derivata non ridefinisce una funzione virtuale, verrà utilizzata la prima ridefinizione presente in ordine inverso diderivazione.

Page 24: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200924

Le funzioni virtuali gerarchiche: esempio 1

class Base {public:virtual void show() { cout<<endl<<”oggetto della classe Base”;};

};

class Derived1 : public Base{public:void show() { cout<<endl<<”oggetto della classe Derived1”;};

};

class Derived2 : public Base{public:// Non viene sostituita show() della base

};

Base *bp;Derived2 d2;

bp = &d2;bp->show(); Viene chiamata la show definita in base

Page 25: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200925

Le funzioni virtuali gerarchiche: esempio 2

class Base {public:virtual void show() { cout<<endl<<”oggetto della classe Base”;};

};

class Derived1 : public Base{public:virtual void show() { cout<<endl<<”oggetto della classe Derived1”;};

};

class Derived2 : public Derived1{public:// Non viene sostituita show() della Derived2

};

Base *bp;Derived2 d2;

bp = &d2;bp->show(); Viene chiamata la show ridefinita in Derived1

Page 26: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200926

Le funzioni virtuali pure

■ Negli esempi precedenti abbiamo visto che quando una funzione non viene ridefinta in una classe derivata, viene impiegata la versione definita nella classe che la precede nell'ordine di derivazione.

■ Spesso però accade che non vi è una definizione appropriata di una funzione virtuale all'interno della classe base. Ad esempio, una classe base potrebbe non essere in grado di definire l'oggetto in maniera sufficiente a consentire la definizione di una funzione nella classe base.

■ Inoltre, in alcuni casi è necessario assicurarsi che tutte le classi derivate ridefiniscano una funzione virtuale.

■ Per gestire questi due casi, il C++ prevede l'uso di funzioni virtuali pure.

Page 27: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200927

Le funzioni virtuali pure

■ Una funzione virtuale pura è una funzione virtuale che non viene definita all'interno della classe base

■ Per definire una funzione viruale pura bisogna usaer la seguente sintassi:virtual Tipo1 nome_funzione(Tipo2, p1, Tipo2 p2, ...) = 0;

■ Quando una funzione virtuale viene resa pura, ogni classe derivata DEVE fornire una propria definizione. La mancata ridefinizione della funzione virtuale pura nella classe derivata provoca una un errore di compilazione.

Page 28: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200928

Le funzioni virtuali pure: esempio

#include derived.h

main(){

Dectype d;Hextype h;Octtype o;

cout<<endl;d.setval(20);d.show();

cout<<endl; h.setval(20);h.show();

cout<<endl; o.setval(20);o.show();

};

class Number {protected:

int val;public:

void set_val(int a){val = a;};virtual void show() = 0;

};

class Hextype : public Number{public:

void show(){ cout<<hex<<val; }};

class Dectype : public Number{public:

void show(){ cout<<val; }};

class Octtype : public Number{public:

void show(){ cout<<oct<<val; }};

201424

output

Page 29: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200929

Le classi astratte

■ Una classe che contiene almeno una funzione virtuale pura è chiamata astratta.

■ Poiché una classe astratta contiene una o più funzioni per le quali non è presente alcuna definizione, non è possibile crare oggetti di quel tipo.

■ In pratica un classe astratta non può essere usata direttamente, ma può essere usata solo come base per definire classi derivate, che hanno appunto l'obbligo di implementare le funzioni virtuali pure ereditate.

■ Osserviamo che anche se non è possibile creare oggetti di classe astratte, è però possibile definire puntatori a classi astratte, al fine di consentire il polimorfismo a run-time.

Page 30: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200930

Uso delle funzioni virtuali pure

■ Abbiamo visto che il polimorfismo consente di definire una classe generale di azioni e in cui l'interfaccia rimane costante e ogni derivazione definisce operazioni specifiche.

■ In pratica è possibile definire una classe base da utilizzare per definire la natura dell'interfaccia di una classe generale (astratta).

■ Ogni classe derivata implementerà le specifiche operazioni in relazione al tipo di dati impiegato da l tipo derivato.

■ Il modo più efficace per sfruttare al meglio le potenzialità del polimorfismo prevede l'uso di:

– Funzioni virtuali;– Classi astratte;– Polimorfismo run-time;

Page 31: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200931

Uso delle funzioni virtuali

■ Utilizzando queste funzionalità è possibile passare da una gerarchia di classi che passi dal caso generale a quello specifico (dalla classe base a quelle derivate).

■ Secondo questa filosofia, si definiscono tutte le funzionalità e i metodi di interfacciamento comuni all'interno della classe base. Nei casi in cui determinate azioni possono essere implementate solo dalla classe derivatasi utilizza una funzione virtuale.

■ In pratica nella classe base si crea e si definisce tutto ciò che fa riferimento alla classe generale. Mentre i dettagli vengono implementati dalle classi derivate.

Page 32: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200932

Uso delle funzioni virtuali: esempio

class convert {protected:

double ini, con;public:

convert(double val){ ini = val;}void set_ini(double val){ ini = val;}double get_ini(){return ini;}double get_con(){return ini;}virtual void compute() = 0;

};

Classeastratta

class lit2gal : public convert{public:

lit2gal(double val): convert(val){} void compute(){

con = ini /3.7854; }

};

class fah2cel : public convert{public:

fah2cel(double val): convert(val){} void compute(){

con = (ini-32)/1.8; }

};

Page 33: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200933

Uso delle funzioni virtuali: esempio#include convert.h

main(){

convert *cp; lit2gal l2g;fah2cel f2c;int choice;

cout<<endl<<”<quale conversione vuoi fare?”cout<<endl<<”1: litri -> galloni”;cout<<endl<<”2: Fahrenheit -> Celsius Derived2”;

cin>>choice;

switch (choice) {case (1): cp = & l2g;

break;case (2): cp = & f2c;

break; }

comp_conv(cp);

};

void comp_conv(convert *c_ptr) {double tmp;

cout<<endl<<”digita valore da convertire:”;cin>>tmp;c_ptr->set_ini(tmp)

c_ptr->compute();

cout<<endl<<”il valore convertito è: ”;cout<<c_ptr->get_conv();

};

Page 34: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200934

Funzioni virtuali: gestione di nuovi casi

■ L'uso del polimorfismo semplifica notevolmente l'estensione dei programmi a nuovi casi.

Esempio

class feet2met : public convert{public:feet2met(double val): convert(val){} void compute(){con = ini /3.28;

}};

Page 35: Ereditarietà e polimorfismo - webuser.unicas.itwebuser.unicas.it/destefano/slides_OOP/L_06_OOP.pdf · Quando si eredita una classe contenente una funzione virtuale, la classe derivata

Claudio De Stefano – Programmazione ad Oggetti - a.a. 2008/200935

Uso del polimorfismo

■ Un utilizzo importante del polimorfismo avviene nelle librerie di classi. È infatti possibile creare una libreria di classi generiche ed estendibili, utilizzabili da altri programmatori.

■ Un altro programmatore, eredita la classe generale, che definise l'interfaccia e tutti gli elementi comuni a tutte le classi da essa derivate, aggiungendo semplicemente le funzioni specifiche della classe derivata.

■ La creazione di librerie di classi astratte consente di creare e controllare l'interfaccia di una classe generale lasciando agli altri programmatori l'adattamento a situazioni specifiche.