La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Introduzione alla programmazione ad oggetti in C++ Object Oriented Programming, OOP E.Mumolo. DEEI

Presentazioni simili


Presentazione sul tema: "Introduzione alla programmazione ad oggetti in C++ Object Oriented Programming, OOP E.Mumolo. DEEI"— Transcript della presentazione:

1 Introduzione alla programmazione ad oggetti in C++ Object Oriented Programming, OOP E.Mumolo. DEEI

2 2 Paradigmi di programmazione Modello procedurale Il mondo della programmazione viene visto come un sistema di processi Modello ad oggetti Il mondo viene visto come un sistema di cose Alcuni temi tipici del modello procedurale: Processi Sequenze di esecuzione Diagrammi di flusso Programmazione top-down Programmazione strutturata Algoritmi=strutture dati + programmazione strutturata Linguaggi strutturati:Fortran, Cobol, Basic, Pascal, C … Operazioni effettuate sui dati inviate alle procedure e alle funzioni sistemi software validi ed efficienti per basse complessità MA : ad alte complessità si evidenzia un cedimento del sistema Una modifica di una struttura dati ha grandi effetti sul sistema campo di visibilità delle strutture dati Riusabilita nei lnguaggi procedurali

3 3 Struttura di un programma Spaghetti code Programmazione strutturata

4 4 Il linguaggio C++ sviluppato alla AT&T da B.Stroustrup (1980) da una idea di Simula65. estensione del C astrazione dei dati Pro: estensione rispetto al linguaggio C Piu adatto del C a progetti complessi prestazioni elevate nonostante la complessità molteplici produttori Contro: linguaggio complesso (non elimina le ridondanze di C, anzi ne introduce) linguaggio ibrido: consente di continuare sviluppare codice tradizionale in C non aiuta a programmare ad oggetti recupero manuale della memoria (Garbage Collection)

5 5 Estensione del C commenti: delimitati da // per commenti su una riga, oltre a /* … */ più adatti a commenti su più righe costanti: variabili di sola lettura specificatore const

6 6 Dichiarazioni variabili: non solo allinizio del programma, ma anche nei cicli Definizione di struttura, enum, unione for(int i=0; i

7 7 Riferimenti (specificatore &) sinonimi (alias) per lo stesso oggetto il tipo delloggetto determina il tipo del riferimento puo essere visto come un tipo speciale di puntatore deve essere inizializzato e agisce solo su un oggetto uso principale: argomenti e risultati di una funzione

8 8 Uso dei riferimenti come argomenti e risultati di funzione senza passare esplicitamente lindirizzo //opp4.cpp #include int incrementa(int &val) { val++; if(val>65000) val=65000; return 0; } int incrementa(int &val, int v) { int t=v; t++; if(t>65000) t=65000; return t; } main() { int i=7; cout << " i=" << i; incrementa(i); cout << " i=" << i << " i=" << incrementa(i,i) << " i=" << i << '\n'; } Output: i=7 i=8 i=9 i=8

9 9

10 10 argomenti di default in una funzione specificatore inline: inline void funzione(..) sostituisce il codice della funzione alle chiamate di funzione. : attenzione alla crescita delle dimensioni del codice! campo di visibilità delle dichiarazioni identificatori dichiarati nelle funzioni sono visibili dalla dichiarazione fino alla fine della funzione identificatori globali sono visibili dalla dichiarazione alla fine del file identificatore locale maschera un identificatore globale con un stesso nome Scope o operatore di visibilità :: specifica la variabile da utilizzare identificatori locali non sono visibili all'esterno della funzione lidentificatore ::var identifica la variabile globale blocco: sequenza di istruzioni tra graffe

11 11 una funzione e un blocco visibilita locale: identificatori definiti allinterno di un blocco visibilita a livello di file: funzioni e identificatori definiti fuori da tutte le funzioni visibilita degli identificatori di blocchi annidati visibilita delle etichette: nel corpo della funzione a cui il blocco appartiene

12 12 Allocazione di oggetti dinamici nella memoria libera Operatore new: argomento tipo delloggetto e ritorna un puntatore alloggetto New restituisce un puntatore nullo in caso di errore Per allocare un array indicare tipo e numero di elementi Operatore delete: rilascia un oggetto in memoria libera Per rilasciare un array: specificatore []

13 13

14 14

15 15

16 16

17 17 //esempio di programmazione C++ : bubble sorting //oop13.cpp #include float arry[10]={15.5, 44, 0.5, -1.5, 65, 0.0, 55.5, 67.0, 5, 3}; struct sistema { float *aa; int ord; }; const int ord=10, ord1=5, ord2=4; // variabili non modificabili! int bubble(float *, int N=ord); void scambia(float &, float &); // passaggio per riferimento void stampa(int); void stampa(float *a, int n=ord); main() { sistema SS[ord1];// definisce l'array SS di 5 strutture 'sistema' sistema *sis = new sistema[ord2]; // alloca in mem. lib. un array di 4 strutture int nl;

18 18 //carica le strutture for(short i=0;i

19 19 int bubble(float *A, int N) { char *flag="notsorted"; int nloop=0; while(!strcmp(flag, "notsorted")){ flag="sorted"; nloop++; for(short i=0;i *(A+i+1)){//A[i] e' *(A+i) scambia(*(A+i),*(A+i+1)); //passa per riferimento!! flag="notsorted"; } return nloop; } void scambia(float &a, float &b) // il compilatore passa l'indirizzo delle var. { float temp=a; a=b; b=temp; } void stampa(int n) { printf("\nArray ordinato (nr. cicli=%d):\n", n); } void stampa(float *a, int n) { for(short j=0;j

20 20 Sovrapposizione delle funzioni (overloading) stesso nome per funzioni diverse, che devono avere argomenti diversi in numero e tipo lo stesso nome deve avere lo stesso tipo di risultato

21 21 Il modello ad oggetti Alcuni temi tipici Dalla astrazione funzionale alla astrazione dei dati Il mondo e modellato non come processi, ma cose Societa di entita attive, cooperanti, riusabili Progettazione bottom-up non top-down Modelli di classi, sottoclassi, istanze di oggetti Linguaggi ad oggetti: Simula, Smalltalk, Eiffel, C++, Java OOP: incapsulamento e mascheramento dei dati limitazione del campo di visibilità delle procedure che manipolano i dati dati e procedure inseparabili oggetto procedure di un oggetto (metodi) attivate inviando messaggi all'oggetto gli oggetti inviano messaggi ad altri oggetti punti fondamentali: tipi di dati astratti, classe, oggetti, incapsulamento, gerarchie di tipi (sottoclassi), ereditarietà, polimorfismo

22 22 OOP focalizza l'attenzione sui dati da manipolare, piuttosto che sulle procedure obiettivi della progettazione e realizzazione di software mediante OOP : migliorare la produttività del programmatore aumentare la versatilità e la riutilizzazione del software controllare la complessità diminuire il costo di manutenzione oggetto = contenitore che racchiude dati e funzioni che gestiscono i dati Information hiding: capacità di oggetti di racchiude dati per eliminare accessi indebiti interfaccia dell'oggetto: indica e pubblicizza le operazioni autorizzate ad accedere i dati implementazione delle funzioni (codice): è in genere nascosto all'interno dell'oggetto un oggetto riceve delle richieste e risponde alle stesse

23 23 classe = definizione astratta delle caratteristiche degli oggetti gli oggetti sono tra loro distinti anche se derivano dalla stessa classe creazione di un oggetto: definizione di una variabile appartenente ad una determinata classe, o definizione di un oggetto di tipo classe nella memoria libera l'interfaccia di una classe è costituita da tutto ciò che non è nascosto in un oggetto. L'interfaccia resta in genere inalterata nel tempo operare con gli oggetti : divisione in componenti che contengono dati e procedure che operano sui dati un oggetto contiene quindi sia la struttura dati che le procedure (metodi) che definiscono il comportamento dell'oggetto stesso le strutture dati sono nascoste all'interno degli oggetti il mondo esterno comunica con i oggetti inviando loro delle richieste (messaggi) per informare l'oggetto su quello che deve essere fatto non su come viene fatto suddivisione del software in classi: un sistema di archiviazione viene chiamato classe archivio con struttura dati e metodi per modificare dati operare con gli oggetti : ogni procedura e associata ad una classe se si aggiungono funzioni di un insieme esistente, si può creare una sottoclasse, creare una nuova classe, o aggiungerle alla classe esistente struttura gerarchica di tipi e sottotipi mediante scomposizione top-down o bottom-up: identificazione e rappresentazione dei dati piu importanti del sistema tramite classi.

24 24 Top-down:esempio Bottom-up: Classe base (componente complesso) Sottoclassi (componenti minime) Automobile ruota carrozzeria motore Classe base (componente minimo) Sottoclassi (componenti via via piu complesse) veicolo Veicolo senza motore Veicolo a motore moto auto taxi aereo

25 25 Classi Una classe (ADT): class casa {... }; Un oggetto e una istanza della classe:casa a; Piu oggetti hanno diversi valori delle variabili e stesso comportamento Piu oggetti hanno diverse variabili, il codice e rientrante: casa a, mia, tua; mia.metodo1 ; //attiva metodo1 mediante linvio dellindirizzo di mia al codice di metodo1 Comunicazione tra oggetti tramite invio di messaggi di attivazione Campo variabili Metodo1 Metodo2 Metodo3 privato pubblico var. a var. mia var. tua Codice dei metodi Puntatore this

26 26 Comunicazione tra oggetti Campo variabili Metodo1 Metodo2 Metodo3 Campo variabili Metodo1 Metodo2 Metodo3 Campo variabili Metodo1 Metodo2 Metodo3 a tua mia Chiama tua.metodo2 Chiama mia.metodo1

27 27 In conclusione Il mondo visto come sistema ad oggetti: societa di entita attive, cooperanti, riutilizzabili Progettazione bottom-up Ereditarieta, polimorfismo Visione globale

28 28 Le classi in C++ una classe è il modello-prototipo-al quale si conformano gli oggetti che istanziano la classe struttura di una classe: class nome_classe { private: // dati e metodi accessibili solo ai metodi della classe. Sono quindi nascosti allesterno (non accessibili direttamente) protected: // privati allesterno; dati e metodi accessibili solo allinterno della classe e tramite classi derivate public: // dati e metodi accessibili pubblicamente a tutte le funzioni dello stesso scope delloggetto }; le componenti funzionali dichiarati in una struttura possono essere definite all'interno, (inline) o all'esterno una classe introduce un nuovo tipo di dati lo specificatore private è implicito scope di una classe: visibilita dei componenti (funzioni e variabili) sintatticamente la classe puo essere vista come una estensione di struct

29 29 il tipo di dato definito con le classi, in cui cioè la struttura interna è inaccessibile, e dal quale si possano istanziare oggetti manipolabili solo per mezzo delle operazione associate, è detto tipo di dato astratto (ADT) esempio di tipo di dato astratto contatore //file contatore.h class contatore { private: unsigned int valore; public: contatore(); //un costruttore void incrementa(); void decrementa(); void set(unsigned int n); unsigned int val(); } l'implementazione della classe può essere realizzato in un file separato o inline

30 30

31 31

32 32

33 33

34 34 Osservazioni i metodi vengono attivati inviando all'oggetto un messaggio con il nome del metodo usando loperatore punto.: c1.incrementa();//invia alloggetto c1 la richiesta di attivare //incrementa c1.visualizza();//analogamente Puntatore ad oggetto: operatore freccia a destra ->:

35 35 Osservazioni (cont.) invio di dati ad una procedura vs. invio di un messaggio all'oggetto ma: quando un oggetto riceve un messaggio, determina come deve essere elaborato il dato sottostante usando i metodi associati al dato non posso elaborare direttamente i dati! Es. c1.valore non è possibile i metodi possono essere definiti anche in più file la classe contatore potrebbe anche essere realizzata con una struttura: #include struct contatore { unsigned int valore; }; main() { contatore c1, c2; c1.valore++; c2.valore++; } ma: in questa forma i dati sono pubblici e la funzione principale accede direttamente al dato sottostante

36 36 struttura dati astratta punto

37 37 Classi annidate (nested) classe interna o nested: definita allinterno di unaltra classe visibilita:allinterno dello scope della classe che la contiene classi definite allinterno di una funzione (scope locale) visibile solo allinterno della funzione

38 38 Costruttori e distruttori delle classi necessità di inizializzare le variabili ciclo di vita di una variabile locale: nello scope in cui e definita ciclo di vita di una variabile dinamica: programma quando viene generata una variabili di tipo classe, si attiva automaticamente una funzione che inizializza le variabili della classe: costruttore quando la variabile termina il suo ciclo di vita viene attivata automaticamente - se disponibile- una funzione di eliminazione: distruttore (ad esempio delete di variabili nella memoria libera) costruttore: funzione con lo stesso nome della classe non richiede tipo di ritorno puo avere una lista di argomenti di inizializzazione attivata automaticamente quando si crea un'oggetto con new sono possibili costruttore diversi, che devono avere liste di argomenti diversi costruttore di default: senza argomenti.

39 39 Costruttore di default funzione senza argomenti formali chiamata dal compilatore quando viene definita una variabile senza inizializzazione speciale nel caso si richeda una inizializzazione speciale costruttore con argomenti

40 40 Costruttore con argomenti: il costruttore da utilizzare dipende dalla lista degli argomenti variabili dinamiche stringa *ps=new stringa(iniziale); //new attiva il costruttore. Se new fallisce, ps punta a //NULL e il compilatore NON attiva il costruttore ps->stampa();...

41 41 Costruttore con argomenti opzionali: #include class stringa { int len; char *str; public: stringa(int a=0, char ch=' ') { len=a; str[len]='\0'; if(a>0) { str=new char[len+1]; for(int i=0; i

42 42 distruttori: funzioni che gestiscono la distruzione del contenuto di oggetti utilizza il nome della classe preceduto da dal carattere ~ attivata automaticamente al termine del ciclo di vita di un'oggetto in genere usati per rilasciare la memoria dinamica oppure per salvare informazioni su file annulla quello fatto dal costruttore libera la memoria addizionale utilizzata dell'oggetto libera le risorse locale e chiude i file aperti libera la memoria dinamica il distruttore, come ogni metodo, può essere chiamato esplicitamente stringa *p=new stringa("nome"); p-> stringa:: ~stringa();

43 43 //esempio di ADT nodo ADT lista //oop23.cpp #include class nodo { private: nodo *next; int valore; public: nodo(){next=NULL;} void loadn(nodo *a){next=a;} void loadv(int a){valore=a;} nodo *getn(){return next;} int getv(){return valore;} }; class lista { private: nodo *head; public: lista(){head=NULL;} //costruttore ~lista(){}//distruttore: lasciato per esercizio! void insert(int n);//at the top void add(int n); //at the bottom int hremove();//toglie dalla cima int tremove();//toglie dalla coda void type();//visita dalla cima e stampa il contenuto };

44 44 void lista::insert(int n) { nodo *temp; temp=new nodo; temp -> loadv(n); temp -> loadn(NULL); if(head) {temp -> loadn(head); head=temp;} else {temp -> loadn(NULL); head=temp;} } void lista::add(int n) { nodo *temp, *prec; if(head){ temp=head; while(temp){ prec=temp; temp=temp->getn(); } prec->loadn(new nodo); prec=prec->getn(); prec->loadv(n); prec->loadn(NULL); } else { head=new nodo; head -> loadv(n); head -> loadn(NULL); }

45 45 int lista::hremove() { int n; if(head){ n=head->getv(); head=head->getn(); return(n); } else return(65536);//65536 means empty } int lista::tremove() { int n; nodo *temp, *prec; temp=head; if(head){ while(temp->getn()) { prec=temp; temp=temp->getn(); } n=temp->getv(); prec->loadn(NULL); delete(temp); return(n); } else return(65536);//65536 means empty }

46 46 void lista::type() { nodo *temp; temp=head; while(temp){ cout getv() << '\n'; temp=temp->getn(); } main() { lista L1, L2; int n; for(int i=0; i<5; i++) L1.insert(i); cout << "L1:" << '\n'; L1.type(); L2.add(10); L2.add(100); cout << "L2:" << '\n'; L2.type(); L1.add(5); L1.add(6); L1.add(7); cout << "L1 after add" << '\n'; L1.type(); cout << "L1hrem " << L1.hremove() << '\n'; while( (n=L2.tremove())!=65536) cout << "L2 trem " << n << '\n'; while( (n=L1.hremove())!=65536) cout << "L1 hrem " << n << '\n'; }

47 47 //esempio di ADT Albero // File Albero.h #define NULL 0 struct nodo { int dato; nodo *sin,*des; }; class Albero { public: Albero() { radice = NULL; } protected: nodo* radice; }; //file AlbRic.h #include "Albero.h #include class AlbRic : public Albero { public: AlbRic() {} ~AlbRic() { Cancella(radice); } void Inserisci(int i) { Aggiungi(i,radice); } void Visita(){ Differito(radice); } private: void Cancella(nodo * &p); void Aggiungi(int i, nodo* &p); void Differito(nodo *p); };

48 48 // File oop24.cpp #include "AlbRic.h" void AlbRic::Cancella(nodo* &p) { if(p!=NULL) { Cancella(p->sin); Cancella(p->des); delete p; } void AlbRic::Differito(nodo * p) { if(p!=0) { Differito(p->sin); Differito(p->des); cout dato << " "; } void AlbRic::Aggiungi(int i, nodo* &p) { if (p == NULL) { p = new nodo; p->dato = i; p->sin = NULL; p->des = NULL; } else if (i dato) Aggiungi(i,p->sin); else if (i > p->dato) Aggiungi(i,p->des); } void main() { AlbRic a; for(int i=0;i<10;i++) a.Inserisci(i); a.Visita(); }

49 49 Autoriferimento nelle classi: l'argomento implicito 'this una classe può contenere oggetti di altre classi, puntatori a oggetti di altre classi, puntatori a oggetti della stessa classe (autoriferimento) ogni oggetto contiene un puntatore, chiamato this, che contiene l'indirizzo dell'oggetto stesso nota: ogni oggetto contiene al proprio interno le variabili definite nella classe, ma non i metodi: ci possono essere molte istanze di una classe ma una sola istanza delle funzioni il puntatore all'oggetto this viene passato implicitamente alle funzioni della classe al momento della loro attivazione, per sapere qual è l'oggetto attivatore

50 50 Possibilità offerta da this : costruire un metodo che ritorna il puntatore al metodo che attivato la funzione #include //oop26.cpp class punto { int x,y; // il compilatore inserisce in modo nascosto:punto *const this; //const perché si vieta alla funzione di alterarne il valore public: punto(){x=0; y=0;}//primo costruttore punto(int a, int b) {x=a; y=b;}//secondo costruttore punto& MuoviPunto(int d1, int d2) {x+=d1; y+=d2; return *this; }; //ritorna l'oggetto stesso punto& Stampa(){cout << " punto= " << x << ", " << y << endl; return *this;} }; main() { punto p1; // crea un'istanza della classe punto e salva il suo indirizzo // nella variabile this=&p1 // attiva il costruttore di default: punto(&p1). // Il costruttore viene implicitamente tradotto come // punto(punto *const this) {this -> x=0; this->y=0;}; punto p2(1,1);//attiva il secondo costruttore: punto(&p2, 1, 1), e modifica in //punto(punto *const this,int a,int b){this->x=a; this->y=b; return;} p2.MuoviPunto(2, 2).Stampa();//diventa possibile l'associazione a sinistra p1.Stampa().MuoviPunto(1,1).Stampa(); } Output: punto= 3, 3 punto= 0, 0 punto= 1, 1

51 51 Altro esempio di autoriferimento: concatenazione di stringhe #include //oop27.cpp class stringa { int len; //dati privati char *str; public: //definizione dei metodi stringa(int=0); stringa(const char *); stringa &concat(const stringa&); char *visualizza(); }; //in questo modo è possibile scrivere: main() { stringa a(80); stringa b("sequenza"); stringa c(" di questa"); stringa d(" prova"); a=b.concat(c).concat(d); cout << a.visualizza(); }

52 52 //implementazione dei metodi stringa::stringa(int n) { len=n; if(n>0){ str=new char (len+1); str[0]='\0'; } } stringa::stringa(const char *s) { len=strlen(s); str=new char[len+1]; strcpy(str,s); } char* stringa::visualizza() { return str; } stringa& stringa::concat(const stringa &s) { len += s.len; char *temp=new char[len+1]; strcpy(temp,str); strcat(temp, s.str);//temp="sequenza di questa" str=temp;//str e' la stringa dell'oggetto che ha attivato concat return *this;//ritorna l'oggetto che ha attivato concat } Output: sequenza di questa prova

53 53 Array di oggetti definizione: contatore c1, c2[100]; c2[10].stampa(); il costruttore e il distruttore vengono chiamati per ciascun elemento dell'array per un vettore di oggetti appartenenti ad una classe con un costruttore, la classe deve avere un costruttore senza argomenti #include //oop28.cpp class punto { int x1, x2; public: punto(int x, int y) {x1=x; x2=y;} punto(){x1=0; x2=0;} void visualizza(){printf("x1, y1 ",x1, x2);} }; main() { punto a(1,2); punto va[20]; for(int i=1;i<20;i++) va[i].visualizza(); }

54 54 Lo specificatore friend aggiunta allincapsulamento e mascheramento. Ma: cautela! normalmente: solo un insieme ben definito di messaggi può essere inviato ad un'oggetto di una classe che deve avere i metodi sufficienti per elaborare i dati 'friend' specifica quali classi esterne possono accedere ai componenti privati //oop29.cpp Esempio: la classe B accede direttamente ai dati privati della classe A #include class A { friend class B;//indicazione unidirezionale!! int uno, due, tre; public: A(){uno=0; due=0; tre=30;}; void inc(){uno++;due++;}; void lst(){cout<<"A::uno="<

55 55 Elementi statici di una classe un elemento dichiarato static, viene condiviso in un'unica copia da tutti i oggetti della classe (normalmente ogni oggetto ha i propri dati!) esempio: per conoscere quanti oggetti di una classe sono stati definiti: #include //oop30.cpp class punto { int x,y; public: static int n_punti; punto(){n_punti++;}; }; int punto::n_punti=0; main() { punto a, b, c; cout << "nr oggetti:" << punto::n_punti << endl; } poiché lelemeto statico è comune tutti gli oggetti, una modifica in un punto modifica tutti gli altri

56 56 Inizializzazione di oggetti Problema: string nome(Luigi); nuovo=nome; Inizializzazione memberwise Costruttore memberwise: nomeclasse::nomeclasse(const nomeclasse&); //oop31.cpp #include class stringa { int len; char *ch; public: stringa(){len=0;} //costruttore di default stringa(const char *s) //costruttore con argomenti; s e' puntatore a stringa costante { len=strlen(s); ch=new char[len+1]; strcpy(ch,s); } stringa(const stringa&s) //costruttore di copia memberwise { len=s.len; ch=s.ch; } void list(){cout<

57 57 uso della inizializzazione memberwise: oggetto1=oggetto2 passaggio argomenti per copia alle funzioni: Class stringa { public: //… int val(){return len;} }; int lung(stringa s){return s.val();} main() { stringa a, b("Luigi"), c=b; c.list(); cout << lung(c); } ritorno per valore di un oggetto: stringa crea(int l) { stringa s; //... return s; //usa liniz. di copia } modalita per riferimento: non richiede copia locale!

58 58 #include //oop32.cpp Esempio di costruttori per copia class stringa { int len; char *ch; public: stringa() {cout << "costruttore di default" << endl; len=0;}//costruttore di default stringa(const char *s) //costruttore con argomenti; s e' puntatore a stringa costante { cout << "costr. con argomenti" << endl; len=strlen(s); ch=new char[len+1]; strcpy(ch,s);} stringa(const stringa&s)//costruttore di copia { cout << "costruttore di copia" << endl; len=s.len; ch=s.ch;} void list(){cout<

59 59 Overloading degli operatori ridefinizione di simboli del linguaggio notazione infissa anche fra tipi diversi limiti: solo operatori gia definiti loperatore che viene ridefinito conserva le sue caratteristiche di associativita, precedenza e numero di argomenti almeno uno degli argomenti deve essere di tipo classe non si possono usare operatori che non hanno significato in C (es. **) Specificatore: operator operatori binari (+,-,*,/) e unari (++, --, +=, etc) operatore binario: definito da un metodo interno con un argomento - a.add(b) – oppure con due argomenti – a=a.add(a,b) - classe C { priv;... public: C binary_op(C); C binary_op(C, C); } classe binary_op(classe arg){return classe(priv+arg.priv);} classe binary_op(classe arg1, classe arg2){ return classe(arg1.priv+arg2.priv);} main(){ a.binary_op(b); a=a.binary_op(a,b); }

60 60 operatore unario: metodo intero ad una classe senza argomenti operatore unario U: l'espressione argomento U oppure U argomento può essere: argomento.U() oppure U(argomento) non è possibile realizzare applicazione prefissa e postfissa /* Uso degli operatori unari e binari */ //oop33.cpp #include void main() { int a=1; int b; cout << "prima a= " << a << '\n'; b = a++; // l'operatore post-incremento e' unario: prima assegna e poi incrementa cout << "dopo a++: a= " << a << " b=" << b <<'\n'; a=1; b = ++a; /* l'operatore pre-incremento e' unario: prima incrementa e poi assegna*/ cout << "dopo ++a: a= " << a << " b=" << b <<'\n'; a=1; b = a+1; /* l'operatore somma e' binario: prima somma e poi assegna */ cout << "dopo a+1: a= " << a << " b=" << b <<'\n'; }

61 61 overloading di operatori unari #include //oop34.cpp class contatore { unsigned int valore; public: contatore(){valore=0;} void operator++(){if(valore<65535) valore++;}//overloading di ++ void operator--(){if(valore>0) valore--;}//overloading di () void operator()(unsigned int n){if((valore>=0)&&(valore<65535)) valore=n;} unsigned int val(){return valore;} }; main() { contatore c1,c2; c2(10); for(short i=0; i<10; i++){ c1++; c2++; } cout << "valore finale di c1=" << c1.val() << " finale di c2=" << c2.val(); } Output: Valore finale di c1=10 finale di c2=20

62 62 numeri complessi //oop35.cpp #include class complesso { private: float pr, pi; public: complesso(){pr=0;pi=0;}//costruttore di default complesso(float x,float y); //altro costruttore void cadd(complesso arg);//operazione binaria void csub(complesso arg);//operazione binaria void cmult(complesso arg); void visualizza(); }; // definizione funzioni complesso::complesso(float x, float y) { pr=x; pi=y; } void complesso::cadd(complesso arg) { pr+=arg.pr; pi+=arg.pi; } void complesso::csub(complesso arg) { pr-=arg.pr; pi-=arg.pi; } void complesso::cmult(complesso arg) { float temp1, temp2; temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; pr=temp1; pi=temp2; }

63 63 void complesso::visualizza() { if(pi<0) cout << '\n' << "complesso: " << pr << "- j" << abs(pi); else cout << '\n' << "complesso: " << pr << "+ j" << pi; } main() { complesso a(1,3), b(2,2); a.visualizza(); b.visualizza(); a.cadd(b); b.cadd(b); a.visualizza(); b.visualizza(); a.csub(b); a.visualizza(); b.visualizza(); a.cmult(b); a.visualizza(); b.visualizza(); } Output: complesso: 1+ j3 complesso: 2+ j2 complesso: 3+ j5 complesso: 4+ j4 complesso: -1+ j1 complesso: 4+ j4 complesso: -8+ j0 complesso: 4+ j4

64 64 seconda versione //oop36.cpp #include class complesso { private: float pr, pi; public: complesso(){pr=0;pi=0;}//costruttore di default complesso(float x,float y); //altro costruttore complesso cadd(complesso arg); complesso csub(complesso arg); complesso cmult(complesso arg); void visualizza(); }; complesso::complesso(float x, float y){ pr=x; pi=y; } complesso complesso::cadd(complesso arg){complesso t; t.pr=pr+arg.pr; t.pi=pi+arg.pi; return t;} complesso complesso::csub(complesso arg){complesso t; t.pr=pr-arg.pr; t.pi=pi- arg.pi; return t;} complesso complesso::cmult(complesso arg) { complesso t; float temp1, temp2; temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; t.pr=temp1; t.pi=temp2; return t; }

65 65 void complesso::visualizza() { if(pi<0) cout << '\n' << "complesso: " << pr << "- j" << abs(pi); else cout << '\n' << "complesso: " << pr << "+ j" << pi; } main() { complesso a(1,3), b(2,2); a.visualizza(); b.visualizza(); a=a.cadd(b); b=b.cadd(b); a.visualizza(); b.visualizza(); a=a.csub(b); a.visualizza(); b.visualizza(); a=a.cmult(b); a.visualizza(); b.visualizza(); }

66 66 overloading degli operatori //oop37.cpp #include class complesso { private: float pr, pi; public: complesso(){pr=0;pi=0;}//costruttore di default complesso(float x,float y); //altro costruttore complesso operator+(complesso arg); complesso operator-(complesso arg); complesso operator*(complesso arg); complesso operator*(float arg); void visualizza(); }; // definizione funzioni complesso::complesso(float x, float y) { pr=x; pi=y; } complesso complesso::operator+(complesso arg) //complesso operator+(complesso b){ co { complesso t; t.pr=pr+arg.pr; t.pi=pi+arg.pi; return t;} complesso complesso::operator-(complesso arg) { complesso t; t.pr=pr-arg.pr; t.pi=pi-arg.pi; return t;}

67 67 complesso complesso::operator*(complesso arg) {complesso t; float temp1, temp2; temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; t.pr=temp1; t.pi=temp2; return t; } complesso complesso::operator*(float arg){ //prodotto con tipo diverso! return complesso(arg*pr, arg*pi); } void complesso::visualizza() { if(pi<0) cout << '\n' << "complesso: " << pr << "- j" << abs(pi); else cout << '\n' << "complesso: " << pr << "+ j" << pi; } main() { complesso a(1,3), b(2,2), c, d; a.visualizza(); b.visualizza(); a=a+b; b=b+b; a.visualizza(); b.visualizza(); a=a-b; a.visualizza(); b.visualizza(); a=a*b; a.visualizza(); b.visualizza(); a=a*2; //attenzione: non e possibile 2*a! a.visualizza(); c=a+a; a=((a+b-c)*c)*2; a.visualizza(); }

68 68 Libreria la classe ostream è definita in stream.h: l'operatore<< viene sovrapposto per gestire l'output di tutti i tipi predefiniti o definita dell'utente. Semplificando : class ostream { private:... public: ostream & operator << (char *ch); ostream & operator << (int i); ostream & operator << (long l);... }; loperazione cout << i puo essere vista come cout.operator<<(i) loperazione cout << i << j; puo essere vista come cout.operator<<(i).operator<<(j)

69 69 Template di classi: classi generiche il concetto di template -modello- e stato introdotto per creare classi generiche //oop38.cpp #include /* implementazione in C++ del tipo di dato astratto STACK tramite array di interi */ class stack { private: int *bottom; // puntatore al fondo dello stack int *top;// puntatore alla cima dello stack public: stack()// costruttore della classe stack { bottom = top = new int[100]; } ~stack()// distruttore della classe stack { delete bottom; } void push (int c) { if ( (top -bottom) < 100 ) *top++ = c; } int pop() { if ( --top >= bottom ) return *top; else return -1; } }; // end class stack void main() { stack s; int i; for (i = 0; i < 10; i++)s.push(i); for (i = 0; i < 10; i++) cout << s.pop(); }

70 70 Problema della classe stack: cambiamento di tipo: //oop39.cpp #include /* implementazione in C++ del tipo di dato astratto STACK tramite array di interi */ class stack { private: double *bottom; // puntatore al fondo dello stack double *top;// puntatore alla cima dello stack public: stack()// costruttore della classe stack { bottom = top = new double[100]; } ~stack()// distruttore della classe stack { delete bottom; } void push (double d) { if ( (top -bottom) < 100 ) *top++ = d; } double pop() { if ( --top >= bottom ) return *top; else return -1; } }; // end class stack void main() { stack s; for (short i = 0; i < 10; i++) s.push(i*3.14); for (short i = 0; i < 10; i++) cout << s.pop() << ' '; }

71 71 //oop40.cpp #include /* tipo di dato astratto STACK di interi e double con TEMPLATE */ template class stack { private: tipo *bottom; // puntatore al fondo dello stack tipo *top;// puntatore alla cima dello stack public: stack()// costruttore della classe stack { bottom = top = new tipo[100]; } ~stack()// distruttore della classe stack { delete bottom; } void push (tipo d) { if ( (top -bottom) < 100 ) *top++ = d; } tipo pop() { if ( --top >= bottom ) return *top; else return -1; } }; // end class stack void main() { stack s1; stack s2; for (short i = 0; i < 10; i++)s1.push(i); for (short i = 0; i < 10; i++)s2.push(i*3.14); cout << "stack di interi: "; for (short i = 0; i < 10; i++) cout << s1.pop() << ' '; cout << "\nstack di double: "; for (short i = 0; i < 10; i++) cout << s2.pop() << ' '; }

72 72 Derivazione di classi l'ereditarietà permette ai programmatori di riutilizzare una classe esistente per costruire una gerarchia di componenti software riutilizzabile personalizzazione della classe d'origine Basi della ereditarietà: la classe derivata; ogni OOP gestisce in modo diverso i dettagli in C++: la classe derivata eredita/modifica tutti i metodi propri della classe d'origine aggiungendo metodi nuovi gestisce una gerarchia di classi derivazione singola una classe può avere un'unica classe d'origine (albero) derivazione multipla una classe puo avere piu classi dorigine visibilità dei dati privati della classe d'origine: una classe derivata NON può accedere ai dati privati a meno che non sia autorizzata farlo con lo specificatore friend o con la modalità protetta (più usata) ogni oggetto di classe derivata ha i propri dati privati e una propria copia di dati privati della classe d'origine sintassi: class ClasseDerivata: ClasseOrigine {... };

73 73 come viene realizzato il processo di ereditarietà? Controllo accesso: indicatori public, private, protected se l'indicatore viene omesso private public: mantiene pubblico, privato, protected nella classe derivata ogni componente rispettivamente pubblico, privato, protected della classe base se la classe base eredita componenti protetti privati li mantiene protetti o privati class Base { int a;// privato nella classe base protected://protetto: int bb; public://pubblico int b; }; class Derivata: public Base { int c; //privato nella classe derivata public: int d;//pubblico int funz(){c=b+bb+d; return c;} } main() { Derivata x; x.d=10; x.b=20; printf(x.funz()); // x.a, x.c non sono accessibili

74 74 //oop41.cpp #include class Persona { protected: int eta; char *nome; public: Persona(const char *n, int e){ nome=new char[strlen(n)+1]; strcpy(nome,n); eta=e; } void presentati(){ cout << "sono una persona, mi chiamo " << nome << "ed ho " << eta << "anni" << endl; } }; class Studente:public Persona { private: int anno; char *facolta; public: Studente(char *n, char *f, int e, int a):Persona(n,e){ facolta=new char[strlen(f)+1]; strcpy(facolta,f); anno=a; } void presentati(){ cout<<"sono uno studente di nome "<

75 75 main() { Persona mario("Mario Verdi", 22); Studente luigi("Luigi Rossi", "ingegneria", 24, 5); mario.presentati(); luigi.presentati(); } sono una persona, mi chiamo Mario Verdi ed ho 22anni sono uno studente di nome Luigi Rossi ho 24 anni e sono iscritto a ingegneria al 5 anno di corso Tutti i metodi della classe dorigine possone essere inviati come messaggio agli oggetti della classe derivata

76 76 Costruttori/distruttore nelle classi derivate legato alla visibilità tra oggetti derivati e oggetti base se un oggetto di classe derivata viene inizializzato, il costruttore deve assicurarsi che venga eseguita una inizializzazione anche dell'oggetto della classe di base-interna alla classe derivata-. il costruttore della classe derivata attiva uno dei costruttore della classe base: class Base { int a; protected: int bb; public: int b; void Base(){a=0;} } class Derivata:public Base { int c; public: Derivata():Base(){c=0;} int funz(){c=c+bb+b+d; return c;} } class Derivata2: public Derivata(){... public: derivata2(): Derivata()}

77 77 //ESEMPIO DI CLASSE BASE //file complesso.h class complesso { protected: float pr, pi; public: complesso(){pr=0;pi=0;}//costruttore di default complesso(float x,float y); //altro costruttore void add(complesso arg); void sub(complesso arg); void mpy(complesso arg); void visualizza(); }; // definizione funzioni complesso::complesso(float x, float y) { pr=x; pi=y; } void complesso::add(complesso arg) //complesso operator+(complesso b){ co { pr=pr+arg.pr; pi=pi+arg.pi; } void complesso::sub(complesso arg) { pr=pr-arg.pr; pi=pi-arg.pi; } void complesso::mpy(complesso arg) { float temp1, temp2; temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; pr=temp1; pi=temp2; } void complesso::visualizza() { if(pi<0) cout << '\n' << "pr,pi " << pr << "- j" << abs(pi); else cout << '\n' << "pr,pi " << pr << "+ j" << pi; }

78 78 //OOP42.cpp #include #include "complesso.h" class comp:public complesso { private: float modulo;//valori trigonometrici float fase; public: comp(float x, float y):complesso(x, y) //costruttore { modulo=sqrt(x*x+y*y); fase=atan(y/x); } void c2t() { float x=pr; float y=pi; modulo=sqrt(x*x+y*y); fase=atan(y/x); } void t2c() { pr=modulo*cos(fase); pi=modulo*sin(fase); } void mult(comp arg) { modulo=modulo*arg.modulo; fase=fase+arg.fase; } void div(comp arg) { modulo=modulo/arg.modulo; fase=fase-arg.fase; } void visualizza() { complesso::visualizza(); cout << " modulo=" << modulo << " fase=" << fase;} }; main() { comp a(1,1); comp b(1,2); a.visualizza(); b.visualizza(); a.mult(b); a.t2c(); a.visualizza(); a.div(b); a.t2c(); a.visualizza(); }

79 79 //oop43.cpp //derivazione #include class complesso { protected: float pr, pi; public: complesso(float x,float y); //altro costruttore complesso cadd(complesso arg); complesso csub(complesso arg); void visualizza(); }; // definizione funzioni complesso::complesso(float x, float y) { pr=x; pi=y; } complesso complesso::cadd(complesso arg) { pr+=arg.pr; pi+=arg.pi; }

80 80 complesso complesso::csub(complesso arg) { pr-=arg.pr; pi-=arg.pi; } void complesso::visualizza() { cout << '\n' << "complesso: " << pr << "+ j" << pi; } class comp: public complesso//derivazione per estendere la classe { public: comp(float x, float y):complesso(x, y){};//costruttore comp cmult(comp arg); comp cdiv(comp arg); void visualizza(char a); }; // comp comp::cmult(comp arg) { float temp1, temp2; temp1=pr*arg.pr - pi*arg.pi; temp2=pr*arg.pi + pi*arg.pr; pr=temp1; pi=temp2; }

81 81 comp comp::cdiv(comp arg) { float temp, temp1, temp2; temp=arg.pr*arg.pr + arg.pi*arg.pi; temp1 = (pr*arg.pr + pi*arg.pi)/temp; temp2 = (pr*arg.pi - pi*arg.pr)/temp; pr=temp1; pi=temp2; } void comp::visualizza(char a) { cout << '\n' << a; complesso::visualizza(); } main() { comp a(1,2), b(2,2); a.complesso::visualizza(); b.complesso::visualizza(); a.cadd(b); b.cadd(b); a.visualizza('a'); b.visualizza('b'); a.csub(b); a.visualizza('a'); b.visualizza('b'); a.cmult(b); a.visualizza('a'); b.cdiv(b); b.visualizza('b'); }

82 82 //OOP44.cppliste derivate #include class nodo { protected: nodo *next; int valore; public: nodo(){next=NULL;valore=0;} void loadpun(nodo *a){next=a;} nodo *getpun(){return next;} void loadval(int a){valore=a;} int getval(){return valore;} }; class nodo_ext: public nodo { protected: char *nome; int flag; public: nodo_ext(char *n, int f):nodo(){strcpy(nome,n);flag=f;} nodo_ext():nodo(){flag=0;nome="";} void loadnome(char *n){nome=new char[strlen(n)+1]; strcpy(nome,n);} char *getnome(){return nome;} void loadflag(int a){flag=a;} int getflag(){return flag;} };

83 83 class lista { private: nodo_ext *head; public: lista(){head=NULL;} //costruttore void add(int val, char *n, int f); //at the bottom int tremove();//toglie dalla coda e restituisce il nome void type();//visita dalla cima e stampa il contenuto }; void lista::add(int val, char *n, int f) { nodo_ext *temp, *prec; if(head){ temp=head; while(temp){ prec=temp; temp=(nodo_ext *)temp->getpun(); } prec->loadpun(new nodo_ext); prec=(nodo_ext*)prec->getpun(); prec->loadval(val); prec->loadflag(f); prec->loadnome(n); prec->loadpun(NULL); } else { head=new nodo_ext; head -> loadval(val); head -> loadflag(f); head -> loadnome(n); head -> loadpun(NULL); }

84 84 int lista::tremove() { int n; nodo_ext *temp, *prec; temp=head; if(head){ while(temp->getpun()) { prec=temp; yemp=(nodo_ext*)temp->getpun(); } n=temp->getval(); prec->loadpun(NULL); delete(temp); return(n); } else return(65536);//65536 means empty } void lista::type() { nodo_ext *temp; temp=head; while(temp){ cout getval() getnome() << " flag=" cout getflag() getpun(); } main() { lista L1, L2; int n; for(int i=0;i<5;i++) L1.add(i,"primo",0); L1.type(); cout << "inizio a rimuovere dalla coda" << '\n'; while((n=L1.tremove())!=65536) cout << "remove L1 " << n << '\n'; }

85 85 Regole di visibilita: Classe base (superclasse) classe derivata (sottoclasse) Ricerca di una componente interna ad una variabile di sottoclasse: Prima nella sottoclasse Poi nelle componenti ereditate Funzioni ridefinite nella sottoclasse:nasconde la funzione della superclasse Tutte le funzioni sono ancora attive! Si possono chiamare o con casting – ((superclasse)oggetto sottoclasse).funzione – o con scope – Oggetto_sottoclasse.superclasse::funzione Riprendiamo la classe Studente. labbinamento funzione-oggetto e fatto STATICAMENTE dal compilatore (allatto della compilazione) sulla base di tipo oggetto e argomenti Ma: con i puntatori? Studente *giorgio; Persona *giulio; giorgio=new Studente(Giorgio Bianchi", "ingegneria", 23,4); giorgio -> presentati(); Attenzione: i puntatori possono puntare a oggetti diversi! giorgio -> presentati(); giulio=giorgio; giulio->presentati(); // la associazione e fatta sulla base del // tipo del puntatore e non delloggetto!! giulio e una persona ma punta ad uno studente! delete giulio cancella solo la persona: spreco spazio Funzioni virtuali: associazione sulla base del tipo di oggetto

86 86 //oop45.cpp #include class Persona { protected: int eta; char *nome; public: Persona(const char *n, int e){ nome=new char[strlen(n)+1]; strcpy(nome,n); eta=e;} virtual void presentati() { cout << "sono una persona, mi chiamo " << nome << " ed ho " << eta << " anni << endl; } }; class Studente:public Persona { private: int anno; char *facolta; public: Studente(char *n, char *f, int e, int a):Persona(n,e) { facolta=new char[strlen(f)+1]; strcpy(facolta,f); anno=a; } virtual void presentati(){ cout<<"sono uno studente di nome "<

87 87 main() { Persona mario("Mario Verdi", 22); Studente luigi("Luigi Rossi", "ingegneria", 24, 5); mario.presentati(); luigi.presentati(); Studente *giorgio; Persona *giulio; giorgio=new Studente("Giorgio Bianchi", "ingegneria", 23,4); giorgio -> presentati(); giulio=giorgio; giulio->presentati(); } Output con funzioni virtuali: sono una persona, mi chiamo Mario Verdi ed ho 22 anni sono uno studente di nome Luigi Rossi ho 24 anni e sono iscritto a ingegneria al 5 anno di corso sono uno studente di nome Giorgio Bianchi ho 23 anni e sono iscritto a ingegneria al 4 anno di corso sono uno studente di nome Giorgio Bianchi ho 23 anni e sono iscritto a ingegneria al 4 anno di corsOutput o Output senza funzioni virtuali sono una persona, mi chiamo Mario Verdi ed ho 22anni sono uno studente di nome Luigi Rossi ho 24 anni e sono iscritto a ingegneria al 5 anno di corso sono uno studente di nome Giorgio Bianchi ho 23 anni e sono iscritto a ingegneria al 4 anno di corso sono una persona, mi chiamo Giorgio Bianchi ed ho 23anni

88 88 Polimorfismo e funzioni virtuali Polimorfismo: capacità di rispondere in modo differenziato agli stessi comandi realizzato con overloading delle funzioni e con le funzioni virtuali overloading delle funzioni: la scelta della funzione da attivare è effettuata esaminando una lista degli operandi o il tipo di oggetti tramite cui vengono operate le richieste alle operazioni abbinamento statico(static binding): deciso alla compilazione abbinamento dinamico(dynamic binding): deciso in run-time overloading quando gli oggetti vengono rappresentati con puntatore: i puntatori possono puntare a oggetti di tipo diverso! ma l'abbinamento statico si basa sul tipo di puntatore e non sul tipo di oggetto puntato! funzione virtuale: funzione il cui abbinamento con l'oggetto è fatto in run-time sintassi: virtual int funz(){ }

89 89 una funzione definita virtuale nella classe base in una gerarchia di derivazione, rende virtuali tutte le funzioni con stesso prototipo e componenti la classe derivata l'abbinamento dinamico oggetto-funzione con le funzioni virtuali funziona solo se gli oggetti sono gestiti con puntatore. Se l'oggetto gestito con il nome, l'associazione e' statica. tre casi in cui la chiamata di una funzione virtuale è risolta staticamente: quando la chiamata e effettuata con un oggetto e non con un puntatore quando si usa scope (::) alla classe nella chiamata con puntatore quando una funzione virtuale è chiamata all'interno di costruttore o distruttore costruttori e distruttori virtuali Un costruttore non puo essere mai dichiarato virtuale (deve essere dichiarato prima) Distruttori possono essere virtuali!

90 90 //oop46.cpp #include class SuperficiePiana { protected: float dim1; public: SuperficiePiana(float d) {dim1=d;} virtual void presentati() { cout << Sono una superficie piana, la mia prima dimensione e' " << dim1 ; } virtual float Area(){ return 0;} }; class triangolo: public SuperficiePiana { private: float dim2; public: triangolo(float d1, float d2) : SuperficiePiana(d1) {dim2=d2; } virtual void presentati() { cout<

91 91 main() { SuperficiePiana * f1; f1=new SuperficiePiana(2.); f1->presentati(); cout Area() << endl; f1=new triangolo(2.,4.); f1->presentati(); cout Area() << endl; } Altra possibilita:... stampa_info(SuperficiePiana *s) { s->presentati(); cout Area() << endl; } main() { SuperficiePiana f1(2); triangolo f2(3,4); cerchio f3(1); stampa_info(&f1); stampa_info(&f2); stampa_info(&f3); }

92 92 //oop47.cpp // aggiunta della classe trapezio class trapezio:public SuperficiePiana { private: float dim2; float dim3; public: trapezio(float d1, float d2, float d3):SuperficiePiana(d1) {dim2=d2;dim3=d3;} void presentati() { cout << "sono un trapezio con basi=" << dim1 << ", " << dim2 << " e altezza= " << dim3 ; } float Area(){return (dim1+dim2)*dim3/2; } }; main() { SuperficiePiana f1(2); triangolo f2(3,4); cerchio f3(1); trapezio f4(2,3,4); stampa_info(&f1); stampa_info(&f2); stampa_info(&f3); stampa_info(&f4); }

93 93 Polimorfismo al lavoro I vantaggi del polimorfismo Esempio: creazione di una ADT lista per realizzare un censimento (categorie di persone, dati sulle persone etc..) Esempio di lista senza polimorfismo senza istruzione friend Esempio di lista senza polimorfismo con istruzione friend Esempio di modifica della lista lista senza polimorfismo e con istruzione friend Esempio di lista polimorfica con istruzione friend Esempio di modifica della lista polimorfica

94 94 Lista non polimorfica senza costrutto friend: header file //lista2.h #include enum tipo_nodo{studente,lavoratore, pensionato} ; struct tipo_studente{ int matricola; int anno_di_corso;}; class nodo { private: char cognome[10]; char nome[10]; int anni; int codice_fiscale; tipo_nodo attivita; union {tipo_studente s; float stipendio; int anni_quiescenza;}; nodo *next; public: nodo(char *co, char *no, int a, int cf, tipo_nodo t); nodo(); void set_attivita(tipo_nodo t); void set_cognome(char *c); void set_nome(char *n); void set_anni(int a); void set_cf(int cf); void set_matricola(int m); void set_anno_corso(int ac); void set_stipendio(float s); void set_quiescenza(int q); void set_next(nodo * t);

95 95 tipo_nodo get_attivita(); char * get_cognome(); char * get_nome(); int get_anni(); int get_cf(); int get_matricola(); int get_anno_corso(); float get_stipendio(); int get_quiescenza(); nodo * get_next(); }; class lista { private: nodo *radice; public: lista(); void insert(nodo *n); void remove(char *c); void stampa(); }; //fine header file lista2.h

96 96 //oop48.cpp. Implementazione dei metodi lista non polimorfica, senza friend #include #include "lista2.h" //implementazione dei costruttori nodo::nodo(char *co, char *no, int a, int cf, tipo_nodo t) { strcpy(cognome,co); strcpy(nome,no); anni=a; codice_fiscale=cf; attivita=t; next=0; } nodo::nodo() { strcpy(cognome,"\0"); strcpy(nome,"\0"); anni=0; codice_fiscale=0; next=0; } //implementazione dei metodi di nodo void nodo::set_attivita(tipo_nodo t) { attivita=t; } void nodo::set_cognome(char *c){ strcpy(cognome,c); } void nodo::set_nome(char *n) { strcpy(nome,n); } void nodo::set_anni(int a) { anni=a; } void nodo::set_cf(int cf) { codice_fiscale=cf; } void nodo::set_matricola(int m) { s.matricola=m; } void nodo::set_anno_corso(int ac) { s.anno_di_corso=ac; } void nodo::set_stipendio(float s) { stipendio=s; } void nodo::set_quiescenza(int q) { anni_quiescenza=q;} void nodo::set_next(nodo * t) { next=t;} tipo_nodo nodo::get_attivita() { return attivita; } char * nodo::get_cognome() { return cognome; } char * nodo::get_nome() { return nome; } int nodo::get_anni() { return anni; } int nodo::get_cf() { return codice_fiscale; } int nodo::get_matricola() { return s.matricola; } int nodo::get_anno_corso() { return s.anno_di_corso; } float nodo::get_stipendio() { return stipendio; } int nodo::get_quiescenza() { return anni_quiescenza;} nodo * nodo::get_next() { return next; }

97 97 //oop48.cpp (continuazione). lista::lista() //implementazione del costruttore di lista { radice=0; } void lista::insert(nodo *n) //implementazione dei metodi di lista { nodo *nuovo, *p, *q; nuovo=new nodo(n->get_cognome(),n->get_nome(),n->get_anni(),n->get_cf(),n->get_attivita()); switch(nuovo->get_attivita()) { case studente: nuovo->set_matricola(n->get_matricola()); nuovo->set_anno_corso(n->get_anno_corso()); break; case lavoratore: nuovo->set_stipendio(n->get_stipendio()); break; case pensionato: nuovo->set_quiescenza(n->get_quiescenza()); break; } nuovo->set_next(0); p=q=radice; if(p==0) {p=radice=nuovo;} else { while(p!=0) {q=p; p=p->get_next();} q->set_next(nuovo); } void lista::remove(char *c) {} //remove non implementata in questa versione per semplicita

98 98 //oop48.cpp (continuazione). void lista::stampa() { nodo *p; p=radice; while(p!=0) { cout get_cognome() get_nome() get_anni() get_cf()<< " "; switch (p->get_attivita()) { case studente: cout << "studente "; cout get_matricola() get_anno_corso() << endl; break; case lavoratore: cout get_stipendio() << endl; break; case pensionato: cout get_quiescenza() << endl; } p=p->get_next(); }

99 99 //oop48.cpp (continuazione e main). main() { //vari modi di creare l'oggetto nodo. 1. mediante il costruttore con argomenti lista l; nodo t("Teseo","Giovanni",70,1234,pensionato); t.set_quiescenza(5); l.insert(&t); //2. mediante i metodi per modificare i campi privati t.set_cognome("Terreni"); t.set_nome("Piero"); t.set_attivita(studente); t.set_anni(30); t.set_cf(2222); t.set_matricola(230); t.set_anno_corso(5); l.insert(&t); //3.mediante puntatori e lo statement new nodo *t1; t1=new nodo("Pallino", "Pinco", 23, 3333, lavoratore); t1->set_stipendio(1000); l.insert(t1); t1=new nodo("Tizio", "Gianni", 33, 3222, lavoratore); t1->set_stipendio(1500); l.insert(t1); l.stampa(); } Output Teseo Giovanni anni 70 CF 1234 pensionato anni di quiescenza5 Terreni Piero anni 30 CF 2222 studente matricola n.230anno di corso 5 Pallino Pinco anni 23 CF 3333 lavoratore stipendio:1000 Tizio Gianni anni 33 CF 3222 lavoratore stipendio:1500

100 100 //lista1.h //lista non polimorfica con uso dello statement FRIEND. Header file: #include enum tipo_nodo{studente,lavoratore, pensionato} ; struct tipo_studente{ int matricola; int anno_di_corso;}; class nodo {friend class lista; private: char cognome[10]; char nome[10]; int anni; int codice_fiscale; tipo_nodo attivita; union {tipo_studente s; float stipendio; int anni_quiescenza;}; nodo *next; public: nodo(char *co, char *no, int a, int cf, tipo_nodo t); nodo(); void set_attivita(tipo_nodo t); void set_cognome(char *c); void set_nome(char *n); void set_anni(int a); void set_cf(int cf); void set_matricola(int m); void set_anno_corso(int ac); void set_stipendio(float s); void set_quiescenza(int q); }; class lista {private: nodo *radice; public: lista(); void insert(nodo *n); void remove(char *c); void stampa(); };

101 101 //oop49.cpp implementazioni dei metodi della lista non polimorfica. #include #include "lista1.h" nodo::nodo(char *co, char *no, int a, int cf, tipo_nodo t) { strcpy(cognome,co); strcpy(nome,no); anni=a; codice_fiscale=cf; attivita=t; next=0; nodo::nodo() { strcpy(cognome,"\0"); strcpy(nome,"\0"); anni=0; codice_fiscale=0; next=0; } void nodo::set_attivita(tipo_nodo t) { attivita=t; } void nodo::set_cognome(char *c) { strcpy(cognome,c); } void nodo::set_nome(char *n) { strcpy(nome,n); } void nodo::set_anni(int a) { anni=a; } void nodo::set_cf(int cf) { codice_fiscale=cf; } void nodo::set_matricola(int m) { s.matricola=m; } void nodo::set_anno_corso(int ac) { s.anno_di_corso=ac; } void nodo::set_stipendio(float s) { stipendio=s; } void nodo::set_quiescenza(int q) { anni_quiescenza=q;} lista::lista() { radice=0; } void lista::insert(nodo *n) { nodo *nuovo, *p, *q; nuovo=new nodo( n->cognome, n->nome, n->anni, n->codice_fiscale, n->attivita ); switch(n->attivita) { case studente: nuovo->s.matricola=n->s.matricola; nuovo->s.anno_di_corso=n->s.anno_di_corso; break; case lavoratore: nuovo->stipendio=n->stipendio; break; case pensionato: nuovo->anni_quiescenza=n->anni_quiescenza; break; } nuovo->next=0; p=q=radice; if(p==0) {p=radice=nuovo;} else { while(p!=0){q=p; p=p->next;} q->next=nuovo; } }

102 102 //oop49.cpp (continua) implementazioni dei metodi della lista non polimorfica. void lista::remove(char *c) {} void lista::stampa() { nodo *p; p=radice; while(p!=0) { cout cognome nome anni codice_fiscale<<" "; switch (p->attivita) { case studente: cout << "studente "; cout s.matricola s.anno_di_corso << endl; break; case lavoratore: cout stipendio << endl; break; case pensionato: cout << "pensionato "; cout anni_quiescenza << endl; } p=p->next; }

103 103 //oop49.cpp (continua) implementazioni del main della lista non polimorfica. main() { lista l; nodo t; t.set_cognome("Teseo"); t.set_nome("Giovanni"); t.set_attivita(pensionato); t.set_anni(70); t.set_cf(1234); t.set_quiescenza(5); l.insert(&t); t.set_cognome("Pierucci"); t.set_nome("Piero"); t.set_attivita(lavoratore); t.set_anni(40); t.set_cf(1111); t.set_stipendio(2000); l.insert(&t); t.set_cognome("Terreni"); t.set_nome("Piero"); t.set_attivita(studente); t.set_anni(30); t.set_cf(2222); t.set_matricola(23); t.set_anno_corso(5); l.insert(&t); l.stampa(); } Output Teseo Giovanni anni 70 CF 1234 pensionato anni di quiescenza5 Pierucci Piero anni 40 CF 1111 lavoratore con stipendio=2000 Terreni Piero anni 30 CF 2222 studente matricola n.23anno di corso 5

104 104 //inserimento nella lista di una categoria aggiuntiva. Lista non polimorfica con friend // lista3.h #include enum tipo_nodo{studente,lavoratore, pensionato, disoccupato} ; //modifica struct tipo_studente{ int matricola; int anno_di_corso;}; struct disocc{ int mesi_disoccupazione; int nr_impieghi;};//modifica class nodo { friend class lista; private: char cognome[10]; char nome[10]; int anni; int codice_fiscale; tipo_nodo attivita; union {tipo_studente s; float stipendio; int anni_quiescenza; disocc dis;}; // modifica nodo *next; public: nodo(char *co, char *no, int a, int cf, tipo_nodo t); nodo(); ~nodo(); void set_attivita(tipo_nodo t); void set_cognome(char *c); void set_nome(char *n); void set_anni(int a); void set_cf(int cf); void set_matricola(int m); void set_anno_corso(int ac); void set_stipendio(float s); void set_quiescenza(int q); void set_disoc(int d); void set_impie(int i); }; class lista { private: nodo *radice; public: lista(); ~lista(); void insert(nodo *n); void remove(char *c); void stampa(); };

105 105 //oop50.cpp //Modifica: inserimento di una categoria aggiuntiva. Implementazione metodi //Lista non polimorfica con friend! #include #include "lista3.h" nodo::nodo(char *co, char *no, int a, int cf, tipo_nodo t) { strcpy(cognome,co); strcpy(nome,no); anni=a; codice_fiscale=cf; attivita=t; next=0; } nodo::nodo() { strcpy(cognome,"\0"); strcpy(nome,"\0"); anni=0; codice_fiscale=0; next=0; } nodo::~nodo(){}; void nodo::set_attivita(tipo_nodo t) { attivita=t; } void nodo::set_cognome(char *c) { strcpy(cognome,c); } void nodo::set_nome(char *n) { strcpy(nome,n); } void nodo::set_anni(int a) { anni=a; } void nodo::set_cf(int cf) { codice_fiscale=cf; } void nodo::set_matricola(int m) { s.matricola=m; } void nodo::set_anno_corso(int ac) { s.anno_di_corso=ac; } void nodo::set_stipendio(float s) { stipendio=s; } void nodo::set_quiescenza(int q) { anni_quiescenza=q;} void nodo::set_disoc(int d) { dis.mesi_disoccupazione=d;} void nodo::set_impie(int i) { dis.nr_impieghi=i;} lista::lista() { radice=0; }

106 106 // oop50.cpp (continua) lista::~lista() { // questo e il metodo piu complesso. Quali sono i due metodi semplici? nodo *p,*q; do{ p=q=radice; while(p->next!=0){q=p;p=p->next;} q->next=0; delete p; } while(q!=radice); delete radice; } void lista::insert(nodo *n) { nodo *nuovo, *p, *q; nuovo=new nodo( n->cognome, n->nome, n->anni, n->codice_fiscale, n->attivita ); switch(n->attivita) { case studente: nuovo->s.matricola=n->s.matricola; nuovo->s.anno_di_corso=n->s.anno_di_corso; break; case lavoratore: nuovo->stipendio=n->stipendio; break; case pensionato: nuovo->anni_quiescenza=n->anni_quiescenza; break; case disoccupato://modifica nuovo->dis.mesi_disoccupazione=n->dis.mesi_disoccupazione; nuovo->dis.nr_impieghi=n->dis.nr_impieghi; break; } nuovo->next=0; p=q=radice; if(p==0) {p=radice=nuovo;} else { while(p!=0){q=p; p=p->next;} q->next=nuovo; } }

107 107 // oop50.cpp (continua) void lista::remove(char *c) {// in questo esempio non e' stata scritta. Si lascia per esercizio } void lista::stampa() { nodo *p; p=radice; while(p!=0) { cout cognome nome anni codice_fiscale<< " "; switch (p->attivita) { case studente: cout << "studente "; cout s.matricola s.anno_di_corso << endl; break; case lavoratore: cout stipendio << endl; break; case pensionato: cout << "pensionato "; cout anni_quiescenza << endl; break; case disoccupato: //modifica cout<<"disoccupato da "; cout dis.mesi_disoccupazione dis.nr_impieghi<next; }

108 108 // oop50.cpp (continua) main() { lista l; nodo t1("Teseo", "Giovanni", 70, 1234, pensionato); t1.set_quiescenza(5); l.insert(&t1); nodo t2("Pierucci", "Piero", 40, 1111, lavoratore); t2.set_stipendio(2000); l.insert(&t2); nodo t3("Terreni", "Piero", 30, 2222, studente); t3.set_matricola(23); t3.set_anno_corso(5); l.insert(&t3); nodo t4("Rossi", "Luigi", 25, 3276, disoccupato); t4.set_disoc(5); t4.set_impie(0); l.insert(&t4); l.stampa(); } Output: Teseo Giovanni anni 70 CF 1234 pensionato anni di quiescenza=5 Pierucci Piero anni 40 CF 1111 lavoratore stipendio=2000 Terreni Piero anni 30 CF 2222 studente matricola nr.23 anno di corso 5 Rossi Luigi anni 25 CF 3276 disoccupato da 5 mesi. nr. impieghi=0

109 109 //lista4.h //lista polimorfica. Header file #include class persona { friend class lista; protected: char cognome[10]; char nome[10]; int anni; int codice_fiscale; persona *ptr; persona *next; public: persona(char *co, char *no, int a, int cf); persona(); ~persona(); void set_cognome(char *c); void set_nome(char *n); void set_anni(int a); void set_cf(int cf); virtual void stampa(); virtual void insert(); };

110 110 //lista4.h (continua) class studente:public persona { friend class lista; private: int matricola; int anno_di_corso; public: studente(char *co, char *no, int a, int cf, int mat, int an):persona(co, no, a, cf) { matricola=mat; anno_di_corso=an; } studente():persona() { matricola=0; anno_di_corso=0;} void set_matricola(int m); void set_anno_corso(int ac); void stampa(); void insert(); }; class lavoratore:public persona { friend class lista; private: float stipendio; public: lavoratore(char *co, char *no, int a, int cf, float s):persona(co, no, a, cf){stipendio=s;} lavoratore():persona() { stipendio=0;} void set_stipendio(float s); void stampa(); void insert(); };

111 111 //lista4.h (continua) class pensionato:public persona { friend class lista; private: int anni_quiescenza; public: pensionato(char *co, char *no, int a, int cf, int q):persona(co, no, a, cf) { anni_quiescenza=q; } pensionato():persona() { anni_quiescenza=0;} void set_quiescenza(int q); void stampa(); void insert(); }; class lista { private: persona *radice; public: lista(); ~lista(); void inserisci(persona *n); void rimuovi(char *c); void stampa(); };

112 112 //oop51.cpp. Lista polimorfica //Implementazione dei metodi della lista polimorfica #include #include "lista4.h" persona::persona(char *co, char *no, int a, int cf) { strcpy(cognome,co); strcpy(nome,no);anni=a; codice_fiscale=cf; next=0; } persona::persona() { strcpy(cognome,"\0"); strcpy(nome,"\0"); anni=0; codice_fiscale=0; next=0; } persona::~persona(){}; void persona::set_cognome(char *c) { strcpy(cognome,c); } void persona::set_nome(char *n) { strcpy(nome,n); } void persona::set_anni(int a) { anni=a; } void persona::set_cf(int cf) { codice_fiscale=cf; } void persona::insert() { ptr=new persona(cognome, nome, anni, codice_fiscale); } void persona::stampa() { cout << cognome << " " << nome << "\t anni " << anni << " CF= " << codice_fiscale ;} void studente::set_matricola(int m) { matricola=m; } void studente::set_anno_corso(int ac) { anno_di_corso=ac;} void studente::stampa() { persona::stampa(); cout << " Studente, matricola=" << matricola << " anno di corso="<

113 113 //oop51.cpp. Lista polimorfica void lavoratore::set_stipendio(float s) { stipendio=s; } void lavoratore::stampa() { persona::stampa(); cout << " Lavoratore, stipendio=" << stipendio <

114 114 //oop51.cpp (continua). Lista polimorfica void lista::inserisci(persona *n) { persona *p, *q; p=q=radice; n->insert(); if(p==0) {p=radice=n->ptr;} else { while(p!=0){q=p; p=p->next;} q->next=n->ptr; } } void lista::rimuovi(char *c) {// in questo esempio non e' stata scritta. Si lascia per esercizio } void lista::stampa() { persona *p; p=radice; while(p!=0) { p->stampa(); p=p->next; } } main() { lista l; persona t; studente st("Terreni", "Piero", 30, 2222, 23, 5); lavoratore la("Pierucci", "Piero", 40, 1111, 2000); pensionato pen("Rossi", "Luigi", 70, 3276, 5); l.inserisci(&st); l.inserisci(&la); l.inserisci(&pen); l.stampa(); }

115 115 //Introduzione di una classe aggiuntiva. Lista polimorfica. Header file //lista5.h #include class persona { friend class lista; protected: char cognome[10];char nome[10];int anni;int codice_fiscale;persona *ptr;persona *next; public: persona(char *co, char *no, int a, int cf); persona(); ~persona(); void set_cognome(char *c); void set_nome(char *n); void set_anni(int a); void set_cf(int cf); virtual void stampa(); virtual void insert(); }; class studente:public persona { friend class lista; private: int matricola; int anno_di_corso; public: studente(char *co, char *no, int a, int cf, int mat, int an):persona(co, no, a, cf) { matricola=mat; anno_di_corso=an; } studente():persona() { matricola=0; anno_di_corso=0;} void set_matricola(int m); void set_anno_corso(int ac); void stampa(); void insert(); };

116 116 //lista5.h (continua) class lavoratore:public persona { friend class lista; private: float stipendio; public: lavoratore(char *co, char *no, int a, int cf, float s):persona(co, no, a, cf) { stipendio=s; } lavoratore():persona() { stipendio=0;} void set_stipendio(float s); void stampa(); void insert(); }; class pensionato:public persona { friend class lista; private: int anni_quiescenza; public: pensionato(char *co, char *no, int a, int cf, int q):persona(co, no, a, cf) { anni_quiescenza=q; } pensionato():persona() { anni_quiescenza=0;} void set_quiescenza(int q); void stampa(); void insert(); };

117 117 //lista5.h (continua) Classe aggiunta nellheader file class disoccupato:public persona { friend class lista; private: int mesi_disoccupazione; int nr_impieghi; public: disoccupato(char *co, char *no, int a, int cf, int md, int ni):persona(co, no, a, cf) { mesi_disoccupazione=md; nr_impieghi=ni; } disoccupato():persona() { mesi_disoccupazione=0; nr_impieghi=0; } void set_disoccupazione(int md) { mesi_disoccupazione=md; } void set_impieghi(int ni) { nr_impieghi=ni; } void stampa() { persona::stampa(); cout << " Disoccupato da " << mesi_disoccupazione; cout << " mesi. Nr. impieghi=" << nr_impieghi << endl; } void insert() { ptr=new disoccupato(cognome,nome,anni,codice_fiscale,mesi_disoccupazione,nr_impieghi); }; class lista { private: persona *radice; public: lista(); ~lista(); void inserisci(persona *n); void rimuovi(char *c); void stampa(); };

118 118 //oop52.cpp //implementazione dei metodi della lista polimorfica #include #include "lista5.h" persona::persona(char *co, char *no, int a, int cf) { strcpy(cognome,co); strcpy(nome,no); anni=a; codice_fiscale=cf; next=0; } persona::persona() { strcpy(cognome,"\0"); strcpy(nome,"\0"); anni=0; codice_fiscale=0; next=0; } persona::~persona(){}; void persona::set_cognome(char *c) { strcpy(cognome,c); } void persona::set_nome(char *n) { strcpy(nome,n); } void persona::set_anni(int a) { anni=a; } void persona::set_cf(int cf) { codice_fiscale=cf; } void persona::insert() { ptr=new persona(cognome, nome, anni, codice_fiscale); } void persona::stampa() { cout << cognome << " " << nome << "\t anni " << anni << " CF= " << codice_fiscale ;} void studente::set_matricola(int m) { matricola=m; } void studente::set_anno_corso(int ac) { anno_di_corso=ac;} void studente::stampa() { persona::stampa(); cout << " Studente, matricola=" << matricola << " anno di corso="<

119 119 //oop52.cpp (continua) void lavoratore::set_stipendio(float s) { stipendio=s; } void lavoratore::stampa() { persona::stampa(); cout << " Lavoratore, stipendio=" << stipendio <

120 120 //oop52.cpp (continua) void lista::stampa() { persona *p; p=radice; while(p!=0) { p->stampa(); p=p->next; } main() { lista l; persona t; studente st("Terreni", "Piero", 25, 2222, 23, 5); lavoratore la("Pierucci", "Piero", 40, 1111, 2000); pensionato pen("Rossi", "Luigi", 70, 3276, 5); disoccupato dis("Ferri", "Luigi", 40, 2323, 8, 1); l.inserisci(&st); l.inserisci(&la); l.inserisci(&pen); l.inserisci(&dis); l.stampa(); }

121 121 Vantaggi del polimorfismo Permette di scrivere codice generico che si adatta automaticamente alle specializzazioni future Permette di creare nuovi metodi senza cambiare il resto del codice Semplice estensione del codice pre-esistente riutilizzabilita del codice Attenzione: se limpostazione e corretta, si puo cambiare molto lavorando poco… …se si modifica troppo il codice originale, limpostazione e sbagliata! Modifiche concentrate migliore manutenzione Attenzione: i vantaggi si pagano con una certa perdita di efficienza!

122 122 Derivazione multipla di classi Finora, le gerarchie di classi erano formate da una unica superclasse Derivazione multipla: pluralita di superclassi Es. superclasse Studente, superclasse Lavoratore sottoclasse Studente- Lavoratore che deriva da entrambe! Inoltre: sia Studente che Lavoratore derivano da Persona Quindi : Persona /\ StudenteLavoratore \/ Studente-Lavoratore Sintassi: class Persona { … } class Studente:public Persona { … } class Lavoratore:public Persona { … } class Studente_Lavoratore:public Studente, public Lavoratore { … }

123 123 //oop53.cppderivazione multipla #include class Persona { protected: int eta; char *nome; public: Persona(const char *n, int e){ nome=new char[strlen(n)+1]; strcpy(nome,n); eta=e;} void presentati() { cout << "sono una persona, mi chiamo " << nome << " ed ho " << eta << " anni" << endl; } }; class Studente:public Persona { private: int anno; char *facolta; public: Studente(char *n, char *f, int e, int a):Persona(n,e) { facolta=new char[strlen(f)+1]; strcpy(facolta,f); anno=a; } void presentati(){ cout<<"sono uno studente di nome "<

124 124 class Lavoratore:public Persona { private: int impresa; float stipendio; public: Lavoratore(char *n, int e, int i, float s):Persona(n,e) { impresa=i; stipendio=s; } void presentati(){ cout<<"sono un lavoratore di nome "<

125 125 main() { Persona mario("Mario Verdi", 22); Studente luigi("Luigi Rossi", "ingegneria", 24, 5); mario.presentati(); luigi.presentati(); Studente *giorgio; Persona *giulio; giorgio=new Studente("Giorgio Bianchi", "ingegneria", 23,4); giorgio -> presentati(); giulio=giorgio; giulio->presentati(); Lavoratore antonio("Antonio Pierucci", 28, 5, 1.7); antonio.presentati(); Stud_Lav piero("Piero Pieri", 28, 6, 1.7, 1, "ingegneria", 1); piero.presentati(); } Output sono una persona, mi chiamo Mario Verdi ed ho 22 anni sono uno studente di nome Luigi Rossi ho 24 anni e sono iscritto a ingegneria al 5 anno di corso sono uno studente di nome Giorgio Bianchi ho 23 anni e sono iscritto a ingegneria al 4 anno di corso sono una persona, mi chiamo Giorgio Bianchi ed ho 23 anni sono un lavoratore di nome Antonio Pierucci ed ho 28 anni. Lavoro in 5 e guadagno 1.7 sono uno studente lavoratore, e sono al corso serale 1


Scaricare ppt "Introduzione alla programmazione ad oggetti in C++ Object Oriented Programming, OOP E.Mumolo. DEEI"

Presentazioni simili


Annunci Google