Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
EREDITARIETA'
es: cellulare (classe cellulare) classe oggetti fisici
es: studente (classe studente) classe persone
Studente ha tutte le proprietà di persona (es: nome, cognome, …) + altre specifiche (es: matricola,
anno immatricolazione, …).
Studente eredità da persona → classe studente deriva da classe persona.
Studente (sottoclasse) → persona (super classe) ← docente
In c++:
Nuova classe “D” in base ad una classe già esistente “B” evidenziando le differenze (con possibilità
di riuso).
“D” derivata, “B” classe base (D → B); ogni campo di “B” (dati e funzioni) è anche campo di “D”
→ D eredita da B.
class B {
public:
int f1() {...}
int f2() {...}
private:
int x;
};
class D: public B { //classe D derivata in modo public da B
public:
int f3() {...}
inf f4() {...}
private:
int y;
};
//derivanza public → visibilità all'esterno della classe D dei campi.
es:
f2 public in B → public in D
x private in B → private in D
uso:
int main() {
D O1;
O1.f3();
O1.f2(); //funzione ereditata
O1.f1(); //funzione f1 di D
O1.B::f1(); //funzione f1 di B
B O2;
O2.f2();
O2.f1();
O2.f3(); //errore -> non posso richiamare funzioni di classi ereditate
} – visibilità campi ereditati all'interno della classe D
– funzioni di D possono riferirsi in modo diretto a tutti i campi pubblici di B, MA non ai
campi privati
Soluzioni:
– usa solo funzioni public di B
– campi in B sono dichiarati protected (invece di private)
Protected: tali campi non sono visibili all'esterno della classe (come i private) ma dalle classi
derivate si.
n.b. I costruttori di B non sono ereditati da D.
class persona {
protected:
string nome, cognome, indirizzo;
...
public:
persona() {
nome = "xxx";
cognome = "xxx";
}
persona (string n); string c) {
n[0] = to_upper(n);
c[0] = to_upper(c);
nome = n;
cognome = m;
...
}
};
class studente: public persona {
private:
int matricola;
string CDL, email;
public:
studente() {
matricola = 0; cdl = "xxx"; email = "xxx";
}
int get_matricola() { return matricola; }
void stampa (ostream & dest) {
dest << nome << " " << cognome << endl;
dest << "Matricola: " << matricola << endl;
dest << "Email: " << email << endl;
}
...
};
int main() {
studente s1;
s1.stampa(cout);
cout << s1.get.matricola();
cout << s1.get.indirizzo();
s1.persona::stampa(cout);
}
studente s2("giacomo", "romani")
– invoca il costruttore senza parametri della classe base
– invoca il costruttore con 2 parametri della classe base con costrutto in generale:
class D: public B {
...
public:
D(..N..): B(..M..) //N e M -> numero dei parametri
{...} // prima invoca il costruttore con M parametri di B
stidenti( string n, string c): persona(n,c) {
col = "informatica";
email = n + "." + c + "@studenti.unipr.it";
matricola = 0;
}
};
int main() {
studente s2("Aldo","Tragni"); //invoca costruttore 2 parametri classe persona
s2.stampa(cout); //Aldo Tragni, matricola 0, email:...
s2.persona::stampa(cout); //Aldo Tragni, indirizzo... , Tel...
}
Principio di sostituibilità
E' possibile usare un oggetto di una classe derivata ovunque sia previsto un oggetto della classe
base (ma non viceversa).
es:
class persona {
...
public:
...
bool operator < (persona P) {
if(cognome == p.cognome)
return nome < p.nome;
return cognome < p.cognome;
}
...
};
class studente: public persona {
...
};
int main() {
studente s1("giacomo","verdi");
studente s2("Aldo","tragni");
if(s1<s2) ... // -> operator < (s2) -> oggetto di classe studente passato come parametro di funzione
della classe persona
}
n.b. La classe derivata è un sottotipo della classe base simile a quello detto per le classi:
ofstream → ostream
Ereditarietà
es: classe data_orario
classe data
→ data del giorno (g,m,a)
classe data_con_orario
→ data + ora del giorno (h,m,s)
con ereditarietà: data_con_orario → data
class data {
protected:
int g,m,a;
void avanza_un_giorno() {...}
private:
bool controlla_data() {...}
public:
data() {...}
data (int giorno, int mese, int anno) {
g = giorno; m = mese; a = anno;
if(controlla_data())
throw "errore data";
}
int get_anno() { return a; }
void stampa(...) {...}
};
class data_con_orario: public data {
private:
int sec;
public:
data_con_orario() { res=0; }
data_con_orario (int g, int m, int a): data(G,M,A) { sec=0; }
void set_orario (int h, int m, int s) {
if(h<0 || h>=24 || m<0 || m>=60 || s<0 || s>=60)
throw "errore orario";
else
sec = h*3600+m*60+s;
}
int get_ore() { return sec%3600; }
int get_minuti() {...}
int get_secondi() { return sec%60; }
void stampa (ostream & dest) {
data::stampa(dest);
if(sec!=0) {
dest << "h";
dest << get_ore() << ":" << get_minuti() << ":" << get_secondi();
}
return;
}
data_con_orario operator+ (int h) {
data_con_orario tmp(g,m,a);
tmp.sec = sec+h*3600;
if(tmp.sec >= 86400) {
int n_giorni = temp.sec/86400;
for(int i=1; i<n_giorni; i++)
tmp.avanza_un_giorno();
tmp.sec = tmp.sec-86400;
}
return tmp;
}
bool operator < (data_con_orario D) { //confronta data dell'oggetto di invocazione con data di D
if(data::operator==(D))
return sec<D.sec;
else
return data::operator<(D);
}
};
Ereditarietà vs contenimento
data_con_orario: definita anche senza ereditarietà con campo data.
class data_con_orario {
private:
data D; //contenimento (N.B. data_con_orario NON è sottoclasse di data)
int sec;
public:
...
};
Svantaggi contenimento
1) Ridefinire tutte le funzioni di data, in data_con_orario (quelle che mi servono)
es: int get_anno() { return d.get_anno(); }
2) Non visibili in modo diretto i campi protected della classe data → per i campi datausare
funzioni public (se ad es: avanza_un_giorno() è protected in data, allora non posso scrivere
“...d.avanza_un_giorno()...” )
3) Non sostituibilità: non posso usare data_con_orario al posto di data in una funzione.
f(data d) → con ereditarietà d può essere sia “data” sia “data_con_orario”
Ereditarietà e template
es:
template <class T>
class B {...}; //classe base
class D1: public B <int> {...}; //classe derivata
template classe t>
class D3: public B <t>
Ereditarietà multipla
In c++ una classe può essere derivata da più classi base data → classe derivata ha i campi di tutte le
classi base + i propri.
data ← data_orario → orario
class data_con_orario: public data, public orario {…};
Gerarchia classi - input output in c++
ios <-- istream - ostream
(Es: istream cin)
(Es: ostream cout,cerr)
istream <-- ifstream
ostream <-- ofstream
fstream --> iostream --> istream,ostream
Es: fstream f1;
f1.grum("prova.txt",ios::read)
Programming in the small vs programming in the large
Programming in the small
- PRoblema affrontato da persona singola.
- Codice di dimensioni limitate.
- Metodologie
- Programmazione strutturata.
- Sviluppo top down.
- strumenti linguistici --> astrazione
- dati
- operazioni (funzioni)
- controllo
Programming in the large
- piú persone
- codice di grandi dimensioni
- sistema
- costituito da piú pezzi (moduli) messi insieme in base ad un oppurtuna architettura software
- Moduli sviluppati
- da persone diverse
- in momenti diversi
- Con problemi di progetto
- Metodologie: programmazione modulare
- strumenti linguistici: costrutti per definire moduli e interfaccie. (es: costrutto di classe)
Modello di sviluppo del software (ciclo di vita del software)
Diverse fasi:
1) raccolta e analisi dei requisiti:
- analisi del problema da risolvere
- cosa deve fare?
- in che ambiente?
- interazione con utente finale
Si ricava un documento dei requisiti (o di specifiche del sistema) formale o informale.
- posso produrre manuale utente e altre specifiche.
2) progettazione (o design)
- Individua componenti del sistema (moduli) e le componenti del sistema (architettura).
- Specifica le diverse funzioniofferte da ciascun modulo (interfaccie)
- specifica del comportamento dinamico del sistema: come evolve lo stato.
In fine si ha un prodotto: schemi concettuali di progetto, con:
- appositi formalismi (grafici) --> es:UML unified modeling language (OOD)
3) realizzazione (o codifica o implementazione): realizzazione del sistema tramite linguaggio
programmazione scelto
- codifica per moduli (nel singolo modulo: programming in the small)
- il prodotto é un programma eseguibile e una documentazione
4) verifica:
1) debugging
- eliminazione di errori run-time
2) testing
- prove del programma su dati campione
--> eventuali feedback (ripetere fasi precedenti in caso di errore)
5) manutenzione e revisione sistema
- conseguenza di errori e mal funzionamenti vari
- cambiamenti nelle specifiche
Analisi -> progettazione -> realizzazione -> verifica -> manutenzione
Da questi passaggi, si crea la documentazione.
6) prototipi
...) altre attivitá
- studio fettibilitá (costi benefici - risorse necessarie).
- gestione del progetto (individuare tempi - fasi - allocazione risorse - suddivisione
compiti)
Progettazione / Programmazione modulare.
Modulo: entitá software raggruppa un insieme di dati e operazioni strettamente correlate tra loro
(coesione alta)
Caratteristiche di ciascun modulo
- Autonomo = debolmente connesso con resto del programma (correlazione bassa)
- Relazione con altri moduli definite in modo preciso
- Definizione precisa dei servizi offerti = interfaccia.
- Interfaccia distinta da implementazione = datie funzioni nel modulo non visibili esternamente
(information hiding)
Ciascun modulo
- Unitá di sviluppo se