Академический Документы
Профессиональный Документы
Культура Документы
a oggetti
Ereditariet
a.a. 2015/2016
Francesco Fontanella
Ereditariet
Meccanismo grazie al quale un oggetto
acquisisce le propriet di un altro oggetto.
Chiama in causa il concetto di classificazione: la
maggior parte della conoscenza resa pi
gestibile da classificazioni gerarchice.
Esempio
una mela rossa Delicious appartiene alla
classificazione mela, che a sua volta appartiene
alla classificazione frutta, che a sua volta si trova
nella classe pi estesa cibo.
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
Esempio
Tipo o classe base: Animale
Tipi derivati (sottoclassi): Cane, Gatto,
Cavallo,
Nel paradigma a oggetti, col meccanismo
dellereditariet ci si concentra sulla
creazione di tassonomie del sistema in
esame
Generalizzazione vs
Specializzazione
Generalizzazione: dal particolare al
generale
Specializzazione o particolarizzazione:
dal particolare al generale
SPECIALIZZAZIONE
GENERALIZZAZIONE
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
Veicolo
Veicolo Senza
Motore
Veicolo
A Motore
Motocicletta
Automobile
Autobus
Taxi
NOTA
Lo stesso sistema pu essere descritto da diverse tassonomie,
a seconda degli obiettivi
Esempio
Automobile
Automobile
Benzina
Berlina
Diesel
Station Wagon
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
Ereditariet e riuso
Il grande vantaggio dell'uso dell'ereditariet
legato al riuso del software.
Pu capitare infatti di disporre del codice di una
classe che non corrisponde esattamente alle
proprie esigenze. Anzich scartare del tutto il
codice esistente e riscriverlo, si pu seguire con
l'ereditariet un approccio diverso, costruendo una
nuova classe che eredita il comportamento di
quella esistente
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
10
classBuilding{
introoms;
intfloors;
floatarea;
public:
voidset_rooms(intr){rooms=r;};
voidset_floors(intf){floors=f;};
voidset_area(floata){area=a;};
intget_rooms(){returnrooms;};
intget_floors(){returnfloors;};
intget_area(){returnarea;};
};
11
12
derivata da
Class Building
classHouse:publicBuilding{
intbedrooms;
intbaths;
public:
voidset_bedrooms(intr){bedrooms=r;};
voidset_baths(intb){baths=b;};
intget_bedrooms(){returnbedrooms;};
intget_baths(){returnbaths;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
13
derivata da
Class Building
classSchool:publicBuilding{
intclassrooms;
intoffices;
public:
voidset_classrooms(intc){classrooms=c;};
voidset_offices(into){offices=o;};
intget_classrooms(){returnclassrooms;};
intget_offices(){returnoffices;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
14
#includehouse.h
#includeschool.h
main()
{
Househ;
Schools;
h.set_rooms(12);
h.set_floors(3);
h.set_area(300);
h.set_bedrooms(5);
h.set_baths(3);
s.set_rooms(46);
s.set_floors(2);
s.set_area(900);
s.set_offices(7);
s.set_baths(3);
.
.
}
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
15
La classe Persona
classPersona{
stringnome,cognome;
public:
Persona(stringn=,stringc=);
voidset_nome(stringstr){nome=str;}
voidset_cognome(stringstr){cognome=str;}
stringget_nome(){returnnome;}
stringget_cognome(){returncognome;}
};
16
La classe studente
classStudente{
stringnome,cognome;
intmatr;
public:
Studente(stringn=,stringc=,intm=0);
voidset_nome(stringstr){nome=str;}
voidset_cognome(stringstr){cognome=str;}
voidset_matr(intm){matr=m;}
stringget_nome(){returnnome;}
stringget_cognome(){returncognome;}
intget_matr(){returnmatr;}
voidshow();
17
voidset_matr(intm){matr=m;}
intget_matr(){returnmatr;}
voidshow();
};
18
Osservazioni
Lereditarieta classica descrive una
relazione del tipo:
un (is-a)
ClassPersona
ClassStudente
19
20
Specificatori di accesso
L'ereditariet viene dichiarata usando la sintassi:
classclasse_derivata:accessoclasse_base
Public;
Private;
Protected
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
21
Lo specificatore public
Quando lo specificatore di accesso public:
Tutti i membri pubblici della classe base
sono pubblici anche nella classe derivata.
22
classBase{
inti,j;
public:
voidset(inta,intb){i=a;j=b};
voidshow(){cout<<i<<<<j;};
};
classDerived:publicBase{
intk;
public:
Derived(inta){k=a;};
voidshowk(){cout<<k;};
voidsetk(){k=i;}// ERRORE!: i privato!
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
23
#includederived.h
intmain()
{
Derivedd(3);
return0;
}
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
24
Lo specificatore private
Quando lo specificatore di accesso private:
25
classBase{
inti,j;
public:
voidset(inta,intb){i=a;j=b};
voidshow(){cout<<i<<<<j;};
};
classDerived:privateBase{
intk;
public:
Derived(inta){k=a;};
voidshowk(){cout<<k;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
26
#includederived.h
main()
{
Derivedd(3);
d.set(1,2);// ERRORE!
d.show();// ERRORE!
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
27
Lo specificatore protected
I membri dichiarati protected non sono
accessibili dall'esterno
A parte un importante eccezione:
lo specificatore protected equivalente
allo specificatore private, nel senso
che tali membri sono accessibili solo da
parte dei membri della classe.
28
29
classBase{
protected:
inti,j;// privato di base, ma accessibile da derived
public:
voidset(inta,intb){i=a;j=b};
voidshow(){cout<<i<<<<j;};
};
classDerived:publicBase{
intk;
public:
voidsetk(){k=i*j;};
voidshowk(){cout<<k;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
30
#includederived.h
main()
{
Derivedd(2,3);
d.show();// membro della classe base
31
Specificatore protected:
ereditariet multipla
Esiste anche la possibilit che una classe
derivata sia a sua volta usata come classe
base per un ulteriore derivazione
In questo caso, tutti i membri protected
della classe base se ereditati come public
dalla prima classe derivata potranno
essere ereditati nuovamente come
protected dalla seconda classe derivata.
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
32
classBase{
protected:
inti,j;
public:
voidset(inta,intb){i=a;j=b};
voidshow(){cout<<i<<<<j;};
};
classDerived1:publicBase{
intk;
public:
voidsetk(){k=i*j;};
voidshowk(){cout<<k;};
};
classDerived2:publicDerived1{
intm;
public:
voidsetm(){m=ij;};
voidshowm(){cout<<m;};
};
33
#includederived.h
main()
{
Derived2d1,d2;
d1.set(2,3);//
d1.setk();//
d2.set(3,4);//
d2.setk();//
d1.show();//
membro di Base
membro di Derived1
membro di Base
membro di Derived1
membro di Base
34
classBase{
protected:
inti,j;
public:
voidset(inta,intb){i=a;j=b;};
voidshow(){cout<<i<<""<<j;};
};
classDerived1:privateBase{
intk;
public:
voidsetk(){k=i*j;};//OK!
voidshowk(){cout<<k;};
};
classDerived2:publicDerived1{
intm;
public:
voidsetm(){m=ij;};// ERRORE!
voidshowm(){cout<<m;};
};
35
#includederived.h
main()
{
Derived1d1;
Derived2d2;
d1.set(2,3);// ERRORE!
d1.setk();
d1.show();// ERRORE!
d2.set(3,4);// ERRORE!
d2.setk();
d2.show();// ERRORE!
d2.showk();
d2.showm();
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
36
37
classBase{
protected:
inti,j;
public:
voidset(inta,intb){i=a;j=b};
voidshow(){cout<<i<<<<j;};
};
classDerived1:protectedBase{
intk;
public:
voidsetk(){k=i*j;};
voidshowk(){cout<<k;};
};
classDerived2:publicDerived1{
intm;
public:
voidsetm(){m=ij;};// OK!
voidshowm(){cout<<m;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
38
#includederived.h
main()
{
Derivedd1,d2;
d1.set(2,3);// ERRORE!
d1.setk();
d1.show();// ERRORE!
d2.set(3,4);// ERRORE!
d2.setk();
d2.show();// ERRORE!
d2.showk();
d2.showm();
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
39
40
classBase{
protected:
inti,j;
public:
voidset(inta,intb){i=a;j=b;}
voidshow(){cout<<i<<""<<j;}
};
classDerived:privateBase{
intk;
public:
usingBase::show;
voidsetk(){k=i*j;}
voidshowk(){cout<<k;}
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
42
Overriding di metodi
classBase{
protected:
inti;
public:
voidshow(){cout<<"showdiBase:"<<endl;}
};
classDerived1:publicBase{
intj;
public:
voidshow(){cout<<"showdiDerived1:"<<endl;}
};
classDerived2:publicDerived1{
intk;
public:
voidshow(){cout<<"showdiDerived2:"<<endl;}
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
43
intmain(){
Baseb,*bp;
Derived1d1,*dp1;
Derived2d2;
b.show();
d1.show();
d2.show();
cout<<endl;
bp=&d1;
bp>show();
bp=&d2;
bp>show();
cout<<endl;
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
SEGUE...
44
dp1=&d2;
OUTPUT
dp1>show();
return0
}
showdiBase
showdiDerived1
showdiDerived2
showdiBase
showdiBase
showdiBase
showdiDerived1
showdiDerived1
45
Object slicing
Per quanto appena visto, possibile inizializzare un
oggetto della classe base con uno di una classe
derivata.
Ci che si ottiene che solo la parte base
dell'oggetto derivata viene assegnato. Si parla di
object slicing.
L'operazione inversa invece illegale: non
possibile assegnare ad un oggetto derivato un
oggetto della classe Base
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
46
intmain(){
Baseb,*bp;
Derived1d1,*dp1;
Derived2d2,*dp2;
// b e pb
b=d1;// OK
b=d2;// OK
bp=dp1;//
bp=dp2;//
bp=&b;//
bp=&d1;//
bp=&d2;//
OK
OK
OK
OK
OK
// d1 e dp1
d1=d2;// OK
dp1=dp2;// OK
dp1=&d1; // OK
dp1=&d2; // OK
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
SEGUE...
47
d1=b;// ERRRORE!
dp1=bp;// ERRRORE!
dp1=&b;// ERRRORE!
// d2 e dp2
dp2=&d2;// OK
d2=b;// ERRRORE!
d2=d1;// ERRRORE!
dp2=bp;// ERRRORE!
dp2=dp1;// ERRRORE!
dp2=&b;// ERRRORE!
dp2=d1;// ERRRORE!
return0;
}
48
49
classBase{
protected:
inti;
public:
voidset_i(inta){i=a;}
};
classDerived1:publicBase{
protected:
intj;
public:
voidset_j(inta){j=a;}
};
classDerived2:publicDerived1{
intk;
public:
voidset_k(inta){k=a;}
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
50
intmain(){
Baseb,*bp;
Derived1d1;
Derived2d2;
bp=&b;
bp>set_i(0);
bp=&d1;
bp>set_i(0);//
bp>set_j(1);//
bp=&d2;
bp>set_i(0);//
bp>set_j(1);//
bp>set_k(1);//
return0;
}
OK!
ERRORE!
OK!
ERRORE!
ERRORE!
51
L'assegnazione di un indirizzo di un
oggetto di una classe derivata ad un
puntatore della classe base pu essere
fatto SOLO se la classe Base stata
ereditata come public, in caso contrario
l'assegnazione vietata
52
classBase{
protected:
inti;
public:
voidset_i(inta){i=a;}
intget_i(){returni;};
};
classDerived:privateBase{
intj;
public:
voidset_j(inta){i=a;}
intget_j(){returni;};
};
53
#includederived.h
main()
{
Base*bp;
Derivedd;
bp=&d;// ERRORE!
};
54
bp=&d;
.
.
((derived*)bp)>set_j(1);//OK
cout<<endl<<((derived*)bp)>get_j();//OK
return0;
};
Francesco Fontanella, Corso di Programmazione
a.a. 2015/2016
55
56
#includederived.h
main()
{
Base*bp;
Derivedd[2];
bp=d;
d[0].set_i(1);
d[1].set_i(2);
cout<<endl<<bp>get_i();
Equivale a
bp++;
bp=bp+sizeof(Base)
Visualizza
cout<<endl<<bp>get_i();
un valore casuale
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
57
Ereditariet multipla
Una classe derivata pu ricevere in eredit
anche due o pi classi base.
Per ereditare da pi classi base si deve
usare un elenco di classi separate da
virgole. Va inoltre utilizzato uno
specificatore per ogni classe ereditata.
58
classBase1{
protected:
intx;
public:
voidshowx(){cout<<x;};
};
classBase2{
protected:
inty;
public:
voidshowy(){cout<<y;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
59
Class Base1
Class Base2
classDerived:publicBase1,publicBase2{
.
.
public:
voidset(inti,intj){x=i;y=j;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
60
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
61
62
63
classBase{
public:
Base(){cout<<"costruzionedibase"<<endl;}
~Base(){cout<<"distruzionedibase"<<endl;}
};
classDerived:publicBase{
public:
Derived(){cout<<"costruzionediderived"<<endl;}
~Derived(){cout<<"distruzionediderived"<<endl;}
};
64
#includederived.h
main()
{
Derivedd;
};
OUTPUT
costruzionedibase
costruzionediderived
distruzionedibase
distruzionediderived
65
Passaggio di argomenti
Nei casi in cui sono solo i costruttori della
classe derivata a richiedere uno o pi
argomenti, si usa la sintassi standard dei
costruttori parametrizzati.
Ma come possibile passare argomenti a una
funzione costruttore di una classe base?
67
68
classBase{
inti;
public:
Base(intx){i=x;cout<<"costruzionedibase,i:"<<i<<endl;}
~Base(){cout<<"distruzionedibase"<<endl;}
};
classDerived:publicBase{
intj;
public:
Derived(intx,inty):Base(y)
{j=x;cout<<"costruzionediderived,j:"<<j<<endl;}
~Derived(){cout<<"distruzionediderived"<<endl;}
};
69
#includederived.h
intmain()
{
Derivedd(3,4);
.
.
return0;
};
OUTPUT
costruzionedibase,i:4
costruzionediderived,j:3
distruzionediderived
distruzionedibase
70
classBase1{
inti;
public:
Base1(intx){i=x;cout<<costruzionedibase1;<<endl};
~Base1(){cout<<distruzionedibase;<<endl};
};
classBase2{
intk;
public:
Base2(intx){k=x;cout<<costruzionedibase2;<<endl};
~Base2(){cout<<distruzionedibase;<<endl};
};
71
Class Base1
Class Base2
classDerived:publicBase1,publicBase2{
intj;
public:
Derived(intx,inty,intz):Base1(y),Base2(z)
{j=x;cout<<costruzionediderived<<endl;};
~Derived(){cout<<distruzionediderived<<endl;};
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
72
73
74
Ereditariet: esempio
Supponiamo di avere a disposizione una classe
Lista
classList{
public:
voidList(){n=0;l=0;}
intsize()const;
intclear();
boolempty()const;
voidinsert(TipoValueval,intpos);
voidremove(intpos);
voidset(TipoValueval,intpos);
TipoValueget(intpos)const;
private:
nodo*l;
intn;
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
75
La classe Pila
// pila.h
#include"Lista.h"
classPila:privateLista{
Public:
usingLista::size;
usingLista::clear;
usingLista::empty;
Pila(){}
voidpush(TipoValueval){insert(val,0);}
TipoValuetop()const{returnget(0);}
TipoValuepop(){
TipoValuetmp=get(0);
remove(0);
returntmp;
}
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
76
La classe Coda
// coda.h
#include"Lista.h"
classCoda:privateLista{
Public:
usingLista::size;
usingLista::clear;
usingLista::empty;
Pila(){}
voidadd(TipoValueval){insert(val,n);}
TipoValuehead()const{returnget(0);}
TipoValuetake(){
TipoValuetmp=get(0);
remove(0);
returntmp;
}
};
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
77
Ereditariet: operatore di
assegnazione
Deve essere realizzato per classi con
estensione dinamica. A differenza degli altri
operatori NON viene ereditato.
Possono verificarsi 4 diversi casi
SEGUE...
Francesco Fontanella, Corso di Programmazione Orientata agli Oggetti
a.a. 2015/2016
78
79
80
81
82
83
84
Composizione
Un'altra possibilit per riusare il codice gi
scritto da altri quella di implementare una
classe che ha come dati membro degli
oggetti di altre classi,
Questa modalit di riuso detta
composizione (composition).
85
Esempio
#include"point.h"
Passaggio di parametri ai
costruttori di copia di p1 e p2
classRetta{
Pointp1,p2;
public:
Retta(Pointo1,Pointo2):p1(o1),p2(o2){}
floatpendenza(){
return(p2.gety()p1.gety())/(p2.getx()p1.getx());
}
};
86
#include"retta.h"
intmain(){
Pointp1(1,1),p2(2,2);
Rettar(p1,p2);
cout<<"Pendenza"<<r.pendenza()<<endl;
}
NOTA
In generale, la composizione implica una relazione
del tipo: has-a (ha-un)
87