La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

1 Introduzione alla programmazione ad oggetti E.Mumolo, DEEI

Presentazioni simili


Presentazione sul tema: "1 Introduzione alla programmazione ad oggetti E.Mumolo, DEEI"— Transcript della presentazione:

1 1 Introduzione alla programmazione ad oggetti E.Mumolo, DEEI

2 2 Paradigmi di programmazione È un punto di vista della programmazione Alcuni paradigmi Programmazione imperativa (lista di istruzioni da eseguire, es. Fortran, C, C++, Java ….) Programmazione non strutturata Programmazione strutturata Programmazione dichiarativa (condizioni logiche, es. Prolog, Lisp …) Programmazione procedurale Programmazione ad oggetti …

3 3 Architetture software Programmazione procedurale Funzione principale Sotto-funzione 1 Sotto-funzione 2 Sotto-funzione 1.2 Sotto-funzione 2.1 Sotto-funzione 2.2Sotto-funzione 1.1

4 4 Programmazione non strutturata Problema: if(9090 A>80 A>70B>50 B>25 B>75 SI

5 5 Programmazione strutturata Codice realizzato mediante combinazione di tre strutture Tutti gli algoritmi possono essere realizzati mediante le tre strutture

6 6 Programmazione strutturata A>90 A>80 A>70B>50 B>25 B>75 SI NN N NAA A

7 7 Programmazione strutturata - pseudocodice if(A>90) then if(B>25) then Accetta else Nonaccetta fi else if(AZ80) then if(B>50) then Accetta else Nonaccetta fi else if(A>70) then if(B>75) then Accetta else Nonaccetta fi

8 8 Programmazione procedurale Modello procedurale Il mondo della programmazione viene visto come un sistema di processi Alcuni temi tipici del modello procedurale: Processi, sequenze di esecuzione Diagrammi di flusso Programmazione top-down Programmazione strutturata Algoritmi=strutture dati + programmazione strutturata Tradizionali linguaggi strutturati: Fortran, 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 linguaggi procedurali

9 9 Esempio: conto corrente Programmazione procedurale: Decomposizione funzionale del problema Divisione del problema in moduli Progetto struttura dati, esempio: Implementazione delle funzioni per operare con i dati, esempio: Deposito(ID,#) Preleva(ID,#) CalcolaInteressi(ID) … Numero correntista Nome correntista Saldo Numero operazioni …… ID correntista

10 10 Approccio orientato agli oggetti: OOA metodologia generale pensare e rappresentare problemi usando concetti del mondo reale oggetti: rappresentano proprietà e comportamenti in una unica entità I modelli possono essere implementati usando un linguaggio di programmazione, un sistema di gestione di archivi, in hardware etc…

11 11 Alcune differenze tra OO e procedurale OOP dati e comportamento contenuti in un oggetto singolo Procedurale dati e comportamento separati OOP divide il problema in oggetti separati che realizzano azioni relazionandosi con altri oggetti Vantaggi proncipali di OOP: Dati e operazioni incapsulati in un oggetto Quando viene creato un nuovo tipo di oggetto, non è necessario modificare le implementazioni precedenti Piuttosto, il nuovo oggetto eredita alcune caratteristiche precedenti Programmi OO sono di più semplice manutenzione

12 12 Esempio: conto corrente Programmazione procedurale: Lattenzione del programmatore è concentrata sulle funzioni che manipolano i dati! Ma: lattenzione di un correntista è più concentrata sui dati che sulle funzioni! Inoltre: Chiunque può modificare i dati (se i dati sono visibili) Funzioni e dati entità separate Punto di vista tradizionale:valore=CalcolaInteressi(ID); funzione argomento valore di ritorno

13 13 Esempio: conto corrente Programmazione ad oggetti : Lattenzione del programmatore è concentrata sui dati non sulle funzioni Dati e funzioni NON sono entità separate programma ad oggetti: insieme di oggetti cooperanti, che sono istanze di un tipo di dati astratto Esempio di tipo di dati astratto per gestire un conto corrente: ContoCorrente Numero correntista Nome correntista Saldo Numero operazioni deposita(valore) preleva(valore) calcolaInteressi() incrementaNumeroOperazioni leggiNumeroOperazioni() dati funzioni

14 14 Esempio: conto corrente Programmazione ad oggetti: Un particolare Conto Corrente è una istanza del tipo do dati astratto Le funzioni sono attivate mediante messaggi. Un particolare ContoCorrente: cosa è visibile dallesterno? Punto di vista ad oggetti:valore=ID CalcolaInteressi(); oggetto funzione valore di ritorno messaggio Oggetto: ContoCorrente Dati privati: Numero correntista Nome correntista Saldo Dati protetti: numero operazioni Dati e funzioni pubbliche: DepositaPrelevaleggiNumeroOperazioniCalcolaInteressi interfaccia

15 15 Esempio: conto corrente Utilizzo delloggetto: oggetto ContoCorrente Messaggio: deposita(x) Messaggio: leggiNumeroOperazioni()

16 16 Cenni di UML UML è un linguaggio (Unified Modeling Language) Fornisce i costrutti per lo sviluppo di sistemi software: Analisi dei requisiti Analisi e progetto OO Modellazione dei componenti Modellazione della struttura e della configurazione Modello espresso mediante diagrammi grafici

17 17 Cenni di UML Diagrammi di UML Diagramma dei casi duso: elenca i casi duso del sistema e le loro relazioni Diagramma delle classi: struttura dati degli oggetti e loro relazioni Diagramma degli oggetti: mostra un insieme di oggetti e loro relazioni Diarammi di interazione: interazioni tra gli oggetti durante scenari di funzionamento Diagrammi di stato e attività: descrive gli stati di un oggetto e le sequenze eventi-azioni-transizioni Diagramma dei componenti: descrive larchitettura fisica del sistema Diagramma di distribuzione: struttura del sistema hardware e allocazione dei vari moduli software

18 18 Cenni di UML Diagrammi dei casi duso: Rappresentano le modalità di utilizzo del sistema da parte degli attori del sistema Descrivono linterazione tra attori e sistema, la logica interna Un attore Spedisce o riceve messaggi dal sistema, o scambia informazioni con esso Esegue i casi duso (funzionalitè percepita da un attore, e sempre attivato da un attore) Corrisponde ad una classe, non ad un oggetto

19 19 Cenni di UML Diagramma dei casi duso in una biblioteca Attore: il cliente Attore: il bibliotecario restituzione prestito prenota Cancella la prenotazione

20 20 Simboli usati per la visibilità ContoCorrente -Numero correntista -Nome correntista -Saldo #Numero operazioni +deposita(valore) +preleva(valore) +calcolaInteressi() -incrementaNumeroOperazioni +leggiNumeroOperazioni() UMLTool di Reverse eng. Tipo di dati astratto=classe istanza di un tipo di dati astratto = oggetto incapsulamento = data hiding = fornisce un livello di astrazione attraverso le funzoni Non cè struttura dati separata: operazioni e struttura dati integrate in una singola entità

21 21 Modelli orientati agli oggetti Modello ad oggetti Il mondo viene visto come un sistema di cose Comportamento visibile Un oggetto Stato interno nascosto Oggetto = stato + comportamento + identità

22 22 Esempio di organizzazione per oggetti Oggetto automobile Oggetto CarrozzeriaOggetto Motore peso = automobile peso() peso = carrozzeria peso() + motore peso()

23 23 Le classi Classificazione: Oggetti con gli stessi attributi e con gli stessi comportamenti sono raggruppati in classi Classe astrazione che descrive delle proprietà Una classe descrive un insieme di oggetti individuali. Un oggetto è una istanza della classe Ogni istanza ha valori diversi degli attributi Le istanze di una classe condividono i nomi degli attributi e le operazioni

24 24 Approccio orientato agli oggetti Esempio di classi: PezzoScacchi (una Torre è un oggetto della classe) Attributi: Colore, Altezza, Posizione Operazioni: Muove Poligono (un Triangolo è un oggetto della classe) Attributi: Vertici, ColoreBordi, ColoreInterno Operazioni: Disegna, Cancella, Muove Bicicletta (la mia bicicletta è un oggetto della classe) Attributi: DiametroRuote, Altezza, Materiale Operazioni: Muove, Ripara, Pulisci

25 25 Passi per la modellazione OO Identificare gli oggetti Identificare il comportamento degli oggetti Identificare le relazioni tra gli oggetti Realizzare gli oggetti: raggruppare in classi le strutture dati ed i comportamenti

26 26 Approccio orientato agli oggetti Caratteristiche di un oggetto: Attributi (struttura dati) Comportamento Caratteristiche richieste da un approccio orientato agli oggetti: Identità(identity) Polimorfismo(polymorphism) Ereditarietà(inheritance)

27 27 Approccio orientato agli oggetti Identità: oggetti distinti: ogni oggetto ha la sua identità anche se i loro attributi sono identici Oggetti: entità concrete (es. un file in un file system) o concettuali (es.: una politica di schedulazione) Oggetti del mondo reale (esempio): due mele – anche se dello stesso colore e forma sono due oggetti distinti -, due gemelli, una persona, un oscilloscopio … Oggetti definiti mediante un linguaggio di programmazione (esempio): un albero binario, una tabella …

28 28 Approccio orientato agli oggetti Polimorfismo: La stessa operazione si comporta diversamente in diverse classi (es. operazione Muovi nella classe PezzoScacchi e Bicicletta). La specifica implementazione di una operazione è chiamata metodo. Polimorfismo=diversi metodi per operatore In un linguaggio orientato agli oggetti il linguaggio seleziona automaticamente il metodo corretto Lutente può non conoscere quanti metodi implementano un operatore

29 29 Approccio orientato agli oggetti Ereditarietà: Creazione di una gerarchia tra le classi Metodo di progetto bottom-up: una super-classe viene definita in modo generico e poi viene perfezionata via via in sotto-classe La super classe fattorizza le proprietà comuni di diverse classi Una sotto-classe eredita tutte le proprietà della sua superclasse e aggiunge altre proprietà Normalmente le proprietà della superclasse non sono ripetute in ogni sottoclasse

30 30 Caratteristiche fondamentali Astrazione Caratteristiche essenziali di una entità Prima di implementare un oggetto, chiedersi cosè e cosa fa Incapsulamento Chiamato anche Information Hiding Separazione degli aspetti esterni (accessibili da oggetti esterni) dalla implementazione interna (nascosti ad oggetti esterni) Rende i programmi robusti dalle piccole variazioni

31 31 Caratteristiche fondamentali Combinazione dei dati e dei comportamenti Approccio convenzionale: procedurale Gerarchia delle strutture dati Gerarchia delle procedure OOA ha una gerarchia unificata Gerarchia delle classi manutenzione più semplice: il codice non deve essere modificato quando viene aggiunta una classe Importanza del polimorfismo: sposta il problema di decidere limplementazione da usare alla gerarchia delle classi Esempio: per disegnare in una finestra, basta chiamare un ipotetico metodo draw. Il metodo corretto viene scelto implicitamente

32 32 Vantaggi della programmazione ad oggetti Protezione delle strutture dati Incapsulamento – information hiding Maggiore semplicità di progettazione astratta progettazione top-down e bottom-up, gerarchia di classi composizione delle classi come mattoni fondamentali Migliore riutilizzazione del codice composizione, aggregazione, derivazione Migliore manutenzione del codice le modifiche sono realizzate mediante aggiunta di classi e funzioni virtuali – non è necessario riprendere e modificare lintero codice Migiore documentazione del codice Strumenti grafici del tipo UML

33 33 Modelli orientati agli oggetti Diagrammi delle classi e delle istanze Attributi Persona Giulio:Persona :Persona Carla : Persona Giulio:Persona nome=Giulio eta=24 peso=70.1 Carla : Persona nome=Carla eta=25 peso=?? Persona Nome: string Età: integer Peso: float

34 34 Modelli orientati agli oggetti Nei diagrammi delle classi: Notazione: Persona Nome Indirizzo Lavoro Cambia_lavoro Cambia_indirizzo File Oggetto geometrico Colore Posizione Nome Dimensione Data_creazione print move(vettore delta) Select(point p):boolean Ruota(angolo) Nome della classe Nome attributo:tipo di dato-1=valore default Nome attributo:tipo di dato-2=valore default … Nome operazione-1 (argomenti):tipo risultato Nome operazione-2 (argomenti):tipo risultato …

35 35 Modelli orientati agli oggetti Operazioni e metodi Funzioni o trasformazioni applicate agli oggetti della classe Tutti gli oggetti della classe condividono le stesse operazioni Ogni operazione opera su un oggetto che può essere implicito o esplicito Un metodo è limplementazione di una operazione Esempio: classe File, operazione print, metodi per stampare file ASCII, binari etc. Polimorfismo: un modo per scegliere il metodo è legato al numero e tipo degli argomenti (sovrapposizione=overloading) Esempio: print(file_name) vs. print(file_pointer) Polimorfismo: il metodo è scelto sulla base delloggetto (aggiramento=overriding)

36 36 Inizializza 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. Un primo metodo: il costruttore della classe

37 37 Relazioni tra oggetti e classi Collegamenti e associazioni Associazione: gruppo di collegamenti con struttura comune Vengono lette in una particolare direzione: I nomi indicano il ruolo di una classe allinterno di una associazione Si interpreta: Stato - HaCapitale - Città Un collegamento è una istanza di una associazione Tipicamente realizzati mediante puntatori HaCapitale CapitaleDi nome Diagramma delle classi Stato Città

38 38 Relazioni tra oggetti e classi: associazione Molteplicità del ruolo della classe Descrive quante istanze di una classe possono relazionarsi ad una singola istanza della classe associata Simboli terminatori: 1 uno e solo uno 0..1 zero o uno (opzionale) M..N da M a N * 0 o più (molti) 0..* 0 o più (molti) 1..* 1 o più (molti) Esempio: punti di intersezione su una linea. Associazione molti-a- molti. Si interpreta: Linea si relaziona con molti Punti; Punto si relaziona con 2 o più Linee 2..** Linea Punto nome

39 39 Relazioni tra oggetti e classi: associazione Società Nome indirizzo Persona Nome Indirizzo Codice fiscale Data di nascita * Datore lavoro impiegato 1 Persona Nome Indirizzo Codice fiscale Data di nascita marito moglie dirigente dipendente 0..1 * personacasa * città possiede poligonolinea 3..* punto ha lati Situata in 1..* * 0..1 * 2

40 40 Esempio di diagramma delle classi Libro -id +inserisci +rimuovi +cerca Titolo -nome -autore -isbn -numeroPrenotazioni +inserisci +rimuovi +cerca Rivista -durataPrestito Prestito Data=dataCorrente +inserisci +rimuovi +cerca Cliente Nome Indirizzo Cerca Inserisci rimuovi Prenotazione -Data=dataCorrente +inserisci +rimuovi +cerca 0..* * Relazioni tra oggetti e classi: associazione n-aria

41 41 Relazioni tra oggetti e classi: associazione n-aria Le associazioni binarie legano due classi. Una classe può legarsi a n classi associazione n-aria. Simbolo: Lezione argomento + Corso Data_inizio Data_fine Aula Giorno e ora Insegnante studenti 1 1 * 1..* 1

42 42 Relazioni tra oggetti e classi Aggregazione: Esprime la forza della associazione o tra classi. Simbolo: Puramente logico Sia il tutto che le parti esistono indipendentemente Asimmetrico, bidirezionale, transitivo Composizione: più forte della aggregazione. Simbolo: Le parti esistono solo in relazione al tutto Persona genitorefiglio * 0..2 AutomezzoMotore 1 1

43 43 Aggregazione Rappresenta un tipo di contenimento tra classi Contenimento lasco: B = contenitore, A = contenuto Contenimento lasco: ciclo di vita oggetto contenuto e contenitore indipendenti il contenitore non è responsabile della creazione e della distruzione delloggetto si realizza mediante un puntatore al contenuto il coordinatore dellaggregazione deve: Creare oggetto contenuto Definire e inizializzare un puntatore ad esso Costruire oggetto contenitore passando puntatore al contenuto

44 44 Composizione Rappresenta un tipo di contenimento tra classi Contenimento stretto: B = contenitore, A = contenuto loggetto contenuto non ha una vita propria loggetto contenitore è responsabile della costruzione e distruzione si realizza con un oggetto contenuto interno al contenitore è responsabilità del coordinatore creare loggetto contenitore fornire valori oggetto contenuto il compilatore richiama il costruttore e il distruttore del contenuto

45 45 Confronto tra contenimento e derivazione Consideriamo i due casi: La classe B contiene la classe A (contenimento) La classe B è derivata dalla classe A (ereditarietà) In entrambi i casi loggetto B contiene loggetto A Interfacce: Contenimento: linterfaccia di A e B indipendenti Derivazione: interfaccia di B comprende quella di A Ereditarietà più forte del contenimento: B può eseguire overriding delle funzioni di A Un puntatore a B può essere assegnato a puntatore a A Un oggetto B può essere assegnato ad un oggetto A

46 46 Esempio di aggregazione tra classi Automobile Marca : stringa Modello : stringa Velocità : float Accelerazione : float MuoviAvanti() MuoviIndietro() MarciaSu() Avvia() Carrozzeria NumeroSerie : stringa Colore : enum […] Peso : float Motore NumeroSerie : stringa Marca : stringa NumeroValvole : enum[…] NumeroCilindri : enum[…] Peso : float Start : Boolean Carrozzeria e Motore hanno vita propria!! Ogni istanza di Automobile ha una Carrozzeria e un Motore Contenimento LASCO

47 47 Associazioni tra classi Associazione uno-a-uno Come si realizza? Con un puntatore alla classe associata Ogni classe ha un metodo collegati al partner Il coordinatore: Crea oggetti a e b Collega a con b Collega b con a associazione

48 48 Associazioni tra classi associazione Ruolo di A Ruolo di B Associazione uno a uno con indicazione dei ruoli Associazione uno a molti associazione * Ad un oggetto della classe A corrispondono più oggetti della classe B Ad un oggetto della classe B corrisponde un oggetto di A Nella classe A cè una lista di puntatori alla classe B lista statica se si conosce il numero massimo di oggetti altrimenti lista dinamica

49 49 Associazioni tra classi Esempio: associazione Persona-Automobile lassociazione possiede ha -Molteplicità 1 a (0..1) una persona possiede 0 o 1 automobile Una automobile è posseduta da 1 persona Direzionalità: da Persona a Automobile (Automobile non ha traccia della associazione) possiede guida 0..1 pilota vettura coproprietario

50 50 Associazioni tra classi lassociazione guida ha Molteplicità 1 a (0..1) una persona può guidare 0 oppure 1 automobile Una automobile è guidata da 1 persona Direzionalità: bidirezionale (Automobile e persona hanno traccia della associazione guida) lassociazione coproprietario Riflessiva Molteplicità 0..1 a 0..1

51 51 Relazioni tra oggetti e classi Molteplicità (esempi) = Persona nome indirizzo nome indirizzo nome indirizzo valutazione coordinatore dipendente coordinatore dipendente Persona nome indirizzo Azienda nome indirizzo Stipendio mansione File Utente nome Permessi

52 52 Esempio (I) Dato il seguente diagramma degli oggetti tracciare il corrispondente diagramma delle classi Punto Poligono Punto Punto 10 Punto -10

53 53 Soluzione esempio (I) Diagramma delle classi Poligono Punto x:coordinata y:coordinata 3..* (ordinata) Note: Il più piccolo nr di punti = 3 Associazione ordinata = indica che i punti sono in sequenza

54 54 Esempio (II) Diagramma degli oggetti per due triangoli con un lato in comune Se un punto appartiene ad un solo triangolo Punto -1,0 Poligono Punto 1.0 Punto 0,1 Punto -1,0 Poligono Punto 1.0 Punto 0,-1

55 55 Esempio (III) Se un punto appartiene ad uno o più triangoli Punto -1,0 Poligono Punto 1.0 Punto 0,1 Poligono Punto 0,-1

56 56 Esempio (IV) Diagramma ad oggetti per descrivere grafi non orientati Grafo non orientato Vertice nome del vertice Lato nome del lato 2 0..*

57 57 Esempio (V) Diagramma ad oggetti per descrivere grafi orientati Grafo orientato Vertice nome del vertice Lato nome del lato da a 0..*

58 Linguaggi di programmazione a oggetti C++ (Stroustrup 83) Ispirato principalmente da Simula67 Java 1. JDK 1.0 (January 23, 1996) JDK 1.0 (January 23, 1996) 2. JDK 1.1 (February 19, 1997) JDK 1.1 (February 19, 1997) 3. J2SE 1.2 (December 8, 1998) J2SE 1.2 (December 8, 1998) 4. J2SE 1.3 (May 8, 2000) J2SE 1.3 (May 8, 2000) 5. J2SE 1.4 (February 6, 2002) J2SE 1.4 (February 6, 2002) 6. J2SE 5.0 (September 30, 2004) J2SE 5.0 (September 30, 2004) 7. Java SE 6 (December 11, 2006) Java SE 6 (December 11, 2006) 1. Java SE 6 Update 10 Java SE 6 Update Java SE 7 Java SE 7 58

59 Integrated Developments Environments Eclipse nal/ nal/ Jbuilder 59

60 60 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 Riferimenti (specificatore &)

61 61 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

62 62

63 63 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: 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 Argomenti di default in una funzione

64 64 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

65 65 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 Le classi in C++

66 66 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 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 Le classi in C++

67 67 Un contatore

68 68 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 ->: Le classi in C++

69 69 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 Le classi in C++

70 70 Strutture dati astratte punto e stringa

71 71 Le classi in C++ Abstract Data Type : classe punto

72 72 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: funzione con lo stesso nome della classe non richiede tipo di ritorno; puo avere una lista di argomenti 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. 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 di copia: Quando si passa o si ritorna un oggetto ad una funzione In generale quando si copia un oggetto Le classi in C++

73 73 #include //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<

74 74 Un numero complesso

75 75 numeri complessi // #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; }

76 76 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); complesso *c; c=new(complesso(3.14,1.2)); a.visualizza(); b.visualizza(); c->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

77 77 ADT nodo ADT lista

78 78 //esempio di ADT nodo ADT lista #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 };

79 79 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); }

80 80 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 }

81 81 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'; }

82 82 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 Le classi in C++

83 83 Le classi in C++ Esempio di autoriferimento: concatenazione di stringhe #include 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(); }

84 84 //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

85 85 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 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); } Le classi in C++

86 86 Operatori del C++ che possono essere sovrapposti: +-*/%^&|~! =<>+=-=*=/=%=^=&= |= >>>= =&& ||++--[]()newdelete Le classi in C++

87 87 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 */ // #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'; } Le classi in C++

88 88 Sovrapposizione degli operatori: esempio

89 89 overloading di operatori unari #include // 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 Sovrapposizione degli operatori: esempio

90 90 Sovrapposizione operatori e numeri complessi // #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; }

91 91 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

92 92 Overloading operatori e numeri complessi: seconda versione // #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; }

93 93 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(); }

94 94 overloading degli operatori e numeri complessi // #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){ { 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;}

95 95 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(); }

96 96 La classe A può dichiarare amica la classe B

97 97 Relazioni tra oggetti e classi: generalizzazione/specializzazione Mammiferi CaniGatti

98 98 Relazioni tra oggetti e classi: generalizzazione/specializzazione Introducono una gerarchia di classe Generalizzazione: una superclasse fattorizza le proprietà comuni di un insieme di classi Generalizzazione: asimmetrica, non riflessiva, transitiva Simbolo: superclasse subclasse Classe più generale Classe meno generale Generalizzazione Specializzazione classi più generali classi più specializzate

99 99 Relazioni tra oggetti e classi: generalizzazione/specializzazione Figura posizione colore display Segmento Coordinate display Rettangolo Vertici display Arco raggio angolo iniziale ancolo finale display Figura posizione colore display Segmento Coordinate display Rettangolo Vertici display Arco raggio angolo iniziale ancolo finale display = Attributi, operazioni e relazioni della superclasse vengono ereditate dalle sottoclassi se protetti

100 100 Top-down: 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 Relazioni tra oggetti e classi: generalizzazione/specializzazione

101 101 Relazioni tra oggetti e classi: generalizzazione/specializzazione Ereditarietà multipla Veicolo a vento Veicolo a motore Veicolo di terra Veicolo dacqua Camion Barca a vela

102 102 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()} Le classi in C++

103 103 Derivazione (I)

104 104 Derivazione (II)

105 105 //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; }

106 106 #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(); }

107 107 // //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; }

108 108 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; }

109 109 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'); }

110 110 Derivazione (III)

111 111 //liste 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;} };

112 112 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); }

113 113 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'; }

114 114 Derivazione (IV) Derivazione multipla

115 115 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 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? Regole di visibilita

116 116 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 Regole di visibilita

117 117 //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 "<

118 118 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

119 119 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(){ } Le classi in C++

120 120 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! Le classi in C++

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 #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<

123 123 main() { SuperficiePiana * f1; f1=new SuperficiePiana(2.); f1->presentati(); cout Area() << endl; f1=new triangolo(2.,4.); f1->presentati(); cout Area() << endl; } //============================================================================ // 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; } };

124 124 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 ogg. a ogg. mia ogg. tua Codice dei metodi Puntatore this Ricapitolando …

125 125 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 Ricapitolando …

126 126 Terminologia: Classe derivata: classe ottenuta mediante specializzazione di unaltra classe Classe base: la classe dalla quale una classe è derivata Ereditarietà: una classe derivata eredita da una classe base Ereditarietà impropria: quando la classe base ha una capacità che la classe derivata non può soddisfare (esempio: nella derivazione struzzo:uccello la classe base ha un metodo vola() ) Costruttori/distruttori: inizializzazione var-rilascio spazio Istanziazione oggetto/terminazione oggetto nome uguale alla classe, senza return parametri opzionali, possibili costruttori multipli Costruttore di default / di copia Attenzione: linizializzazione del costruttore segue lordine di definizione variabili Ricapitolando …

127 127 Ereditarietà Relazione has-a (composizione) Relazione is-a (specializzazione/derivazione) Esempio: Se il problema si descrive con la frase : … un veicolo contiene una o più ruote… Implementare la classe ruota e poi la classe veicolo: class veicolo{ private: Ruota r1,r2,r3; } Se si descrive con la frase: …unauto è un veicolo… Implementare la classe veicolo e poi la classe auto: class auto:public veicolo{ private:... } auto *a=new auto(); veicolo *v=new veicolo(); v=a; //lecito a=v; //errato Ricapitolando …

128 128 Array di oggetti: 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 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 Ricapitolando …

129 129 Polimorfismo: Capacità degli oggetti di differenti classi legate da ereditarietà di rispondere differentemente alla stessa chiamata Ottenuto mediante overloading delle funzioni e funzioni virtuali Abbinamento statico delle funzioni agli oggetti Statico: legato al tipo del puntatore, non al tipo delloggetto puntato casting per indicare esplicitamente il tipo del puntatore Funzioni virtuali : Abbinamento dinamico della funzione alloggetto I costruttori NON possono essere virtuali I distruttori possono invece esserlo: recuperano lo spazio delloggetto puntato Ricapitolando …

130 130 Funzioni virtuali come base per la derivazione: Non definiscono il contenuto di alcuni metodi: Public:virtual void stampa(){ }; Funzioni virtuali pure Definite ma mai utilizzate per istanziare oggetti Dichiarate con uno zero: Public:virtual void stampa() = 0; Classe che contiene una o più funzioni virtuali pure : classe astratta (indica comè fatta la classe in modo astratto) Usata come base per la derivazione Non è possibile istanziare da una classe astratta Una classe astratta è una interfaccia per la derivazione Ricapitolando …

131 131 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 Polimorfismo e funzioni virtuali

132 132 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! Polimorfismo e funzioni virtuali

133 133 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!

134 134 Polimorfismo (I)

135 135 Polimorfismo (II)

136 136 Lista non polimorfica senza friend

137 137 Lista non polimorfica con friend

138 138 Inserimento di una categoria aggiuntiva nella lista non polimorfica

139 139 Lista polimorfica

140 140 // //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(); };

141 141 //(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(); };

142 142 //(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(); };

143 143 //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="<

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

145 145 //(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(); }

146 146 //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(); };

147 147 //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(); };

148 148 //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(); };

149 149 //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="<

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

151 151 //(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(); }

152 152 Esempio di calcolo con i polinomi mediante programmazione ad oggetti

153 153 class CFunction{ public: CFunction(){ if (dbg) cout << "Costruttore classe base CFunction" << endl;} virtual ~CFunction(){ if (dbg) cout << "Distruttore classe base CFunction" << endl;} virtual double GetY(double x) = 0; }; class CPoly: public CFunction{ protected: int Order; //Grado del polinomio double *Coeffs; public: CPoly(); //C default crea ma non definisce ordine e coefficienti CPoly(int g, double* c); //C numeratore grado g e coefficienti di *c, denominatore 1 CPoly(const CPoly& p); //C di copia CPoly(int g, double c); //costruttore di polinomio grado 0 coeff=c ~CPoly(); //Distruttore void Visualizza()const; //stampa CPoly &operator=(const CPoly& p); CPoly operator+(const CPoly& p); CPoly operator-(const CPoly& p); CPoly operator*(const CPoly& p); int GetOrder(); double GetCoeffs(int i); bool nullo(); //verifica se il polinomio è nulloù bool unitario(); double GetY(double x){} };

154 154 class CPolyF: public CPoly{ //definisce polinomio base protected: char *nome; //nome del polinomio int OrderF; //Grado del polinomio double *CoeffsF; //Vettore di coefficienti public: CPolyF(); //C default crea ma non definisce ordine e coefficienti CPolyF(int g, double* c); //C numeratore grado g e coefficienti di *c, denominatore 1 CPolyF(int g, double* c, int gF, double *cF); //C numeratore grado g e coefficienti di *c, denominatore 1 CPolyF(const CPolyF& p); //C di copia CPolyF(const CPoly& a, const CPoly& b); //C per parti CPolyF(const CPoly& a); //C polinomi interi ~CPolyF(); //Distruttore void Visualizza()const; //stampa CPolyF &operator=(const CPolyF& p); //assegnazione CPolyF operator+(const CPolyF& p); //somma CPolyF operator-(const CPolyF& p); //differenza CPolyF operator*(const CPolyF& p); //moltiplicazione CPolyF operator/(const CPolyF& p); //divisione void SetNome(char *n); //assegna il nome al polinomio void SetNum(CPoly n); void SetDen(CPoly d); char* GetNome(); void Semplifica(); //ricerca fattori semplificabili //CPoly GetDen(); double GetY(double x){} //friend class CPolyF; };

155 155 CPoly::CPoly(int g, double* c){ //Costruttore int i=0; for (i=g; i>0; i--){ //i coefficienti sono congruenti con il grado? if (c[i]==0) g--; else break; }//end for Order=g; if (g>=0){ Coeffs=new double[g+1]; for (i=0; i<=g; i++){ Coeffs[i]=c[i]; } else Coeffs=NULL; } CPoly::~CPoly(){ //distruttore if (Coeffs) delete [] Coeffs; //se è definito CoeffsF lo dealloca } void CPoly::Visualizza()const{ if (Order<0){ //polinomio definito? cout << "Polinomio non definito" << endl; return; }//end if stampa(Order, Coeffs); //stampa del solo numeratore //e stampa il risultato cout << endl; //a capo } CPoly &CPoly::operator=(const CPoly& p){ if (Order!=p.Order){ if (Coeffs) delete [] Coeffs; Order=p.Order; Coeffs=new double[Order+1]; } //copia dei coefficienti for (int i=0; i<=Order; i++) Coeffs[i]=p.Coeffs[i]; if (dbg) cout << "\nOperatore CPoly =" << endl; return *this; }

156 156 CPolyF::CPolyF():CPoly(){ //Costruttore di default nome=NULL; OrderF=-1; //denominatore CoeffsF=NULL; //nè per numeratore nè per denominatore if (dbg) cout << "C CPolyF default" << endl; //debug } CPolyF &CPolyF::operator=(const CPolyF& p){ //se gli ordini sono diversi si devono riallocare i coefficienti if (Order!=p.Order){ if (Coeffs) delete [] Coeffs; //deallocando i precedenti Order=p.Order; //acquisendo il nuovo ordine Coeffs=new double[Order+1]; //e allocando quelli nuovi } //copia dei coefficienti for (int i=0; i<=Order; i++) Coeffs[i]=p.Coeffs[i]; if (OrderF!=p.OrderF){ if (CoeffsF) delete [] CoeffsF; //deallocando i precedenti OrderF=p.OrderF; //acquisendo il nuovo ordine CoeffsF=new double[OrderF+1]; //e allocando quelli nuovi } //copia dei coefficienti for (int i=0; i<=OrderF; i++) CoeffsF[i]=p.CoeffsF[i]; if (dbg) cout << "\nOperatore CPolyF =" << endl; return *this; }

157 157 CPolyF CPolyF::operator-(const CPolyF& p){ CPolyF ris; bool den_uguali=true; CPoly *n1, *d1, *n2, *d2; if (OrderF==p.OrderF){ for (int i=0; i<=p.OrderF; i++){ if (CoeffsF[i]!=p.CoeffsF[i]) den_uguali=false; } if (den_uguali){ n1=new CPoly(Order, Coeffs); n2=new CPoly(p.Order, p.Coeffs); d1=new CPoly(OrderF, CoeffsF); ris=CPolyF((*n1)-(*n2),(*d1)); delete n1, n2, d1; return ris; } n1=new CPoly(Order, Coeffs); d1=new CPoly(OrderF, CoeffsF); n2=new CPoly(p.Order, p.Coeffs); d2=new CPoly(p.OrderF, p.CoeffsF); ris=CPolyF((*n1)*(*d2)-(*n2)*(*d1),(*d1)*(*d2)); delete n1, n2, d1, d2; return ris; } CPolyF CPolyF::operator+(const CPolyF& p){ CPolyF ris; bool den_uguali=true; CPoly *n1, *d1, *n2, *d2; if (OrderF==p.OrderF){ for (int i=0; i<=p.OrderF; i++){ if (CoeffsF[i]!=p.CoeffsF[i]) den_uguali=false; } if (den_uguali){ n1=new CPoly(Order, Coeffs); n2=new CPoly(p.Order, p.Coeffs); d1=new CPoly(OrderF, CoeffsF); ris=CPolyF((*n1)+(*n2),(*d1)); delete n1, n2, d1; return ris; } n1=new CPoly(Order, Coeffs); d1=new CPoly(OrderF, CoeffsF); n2=new CPoly(p.Order, p.Coeffs); d2=new CPoly(p.OrderF, p.CoeffsF); ris=CPolyF((*n1)*(*d2)+(*n2)*(*d1),(*d1)*(*d2)); delete n1, n2, d1, d2; return ris; }

158 158 CPolyF CPolyF::operator*(const CPolyF& p){ CPolyF ris; bool n1_d2_uguali=true; bool n2_d1_uguali=true; CPoly *n1, *d1, *n2, *d2; if (Order==p.OrderF){ //controllo uguaglianza num1-den2 for (int i=0; i<=p.OrderF; i++){ if (Coeffs[i]!=p.CoeffsF[i]){ n1_d2_uguali=false; break; } else n1_d2_uguali=false; if (n1_d2_uguali){ n1=new CPoly(0, 1); d2=new CPoly(0, 1); } else{ n1=new CPoly(Order, Coeffs); d2=new CPoly(p.OrderF, p.CoeffsF); } //fine uguaglianza num1-den2 if (OrderF==p.Order){ //controllo uguaglianza num2-den1 for (int i=0; i<=p.Order; i++){ if (CoeffsF[i]!=p.Coeffs[i]){ n2_d1_uguali=false; break; } else n2_d1_uguali=false; if (n2_d1_uguali){ n2=new CPoly(0, 1); d1=new CPoly(0, 1); } else{ n2=new CPoly(p.Order, p.Coeffs); d1=new CPoly(OrderF, CoeffsF); } //fine uguaglianza num2-den1 ris=CPolyF((*n1)*(*n2),(*d1)*(*d2)); delete n1, n2, d1, d2; return ris; }

159 159 Esempio di calcolo vettoriale mediante programmazione ad oggetti

160 160 #include //stream di input e output #include //libreria standard #include //console di input e output #include //libreria con funzioni matematiche (radice) typedef int inte; //Il vettore é di tipo intero class matrix //classe matrice { //definita da righe,colonne e dove sono colocate friend class vettore; //classe vettore può usare oggetti matrice protected: //protette per derivazione int r,c; //variabili numero righe(r) e colonne(c) int **m; //doppio puntatore public: matrix(int a,int b); //costruttore con argomenti numero righe e colonne matrix(matrix& y); //costruttore copia virtual inte& accedi(int i,int j); //accesso alle variabili:ne restituisce il valore matrix operator+(matrix& mat); //somma di 2 matrici;overloading di + matrix operator-(matrix& mat); //sottrazione di 2 matrici;overloading di - matrix operator*(matrix& mat); //moltiplicazione di 2 matrici;overloading di * void errore(char c[]); //segnala l'errore e esci dal programma virtual void stampa(char *s1); //visualizza la matrice };//matrix matrix::matrix(int a,int b) //costruttore { r=a; //assegna numero di righe c=b; //assegna numero di colonne m=new inte*[r]; //crea un "oggetto" di r puntatori,poi ad ogni puntatore for(int i=0;i

161 161 class matrice_quad:public matrix //matrice quadrata,sottoclasse di matrice:è un esempio di derivazione { //questo programma non richiede la dichiarazione friend,poiché nel main la classe vettore private: //non usa oggetti matrice_quad bool sim,diag; //variabili simmetrica e diagonale public: matrice_quad(int a,int b,bool si,bool dia):matrix(a,b) //costruttore che prende in { //derivazione numero di righe e di colonne(=righe) dal costruttore della superclasse matrice sim=si; //inizializzate le variabili simmetrica e diagonale diag=dia; }//costruttore matrice_quad(matrice_quad& x):matrix(x) //costruttore copia con derivazione { //delle protected di matrice e sim=x.sim; //private di matrice quadrata diag=x.diag; }//costruttore copia void check_sim(); //controlla se simmetrica void check_dia(); //controlla se diagonale inte& accedi(int i,int j); //accedi alle variabili void errore(char c[]); //segnala l'errore e esci dal programma void stampa(char *s1); //visualizza la matrice quadrata };//matrice_quad class vettore //classe vettore { //definita dal numero di elementi(size) e dove sono collocati(*p) private: int size; //quanti elementi ci sono inte *p; //dove sono questi elementi public: vettore(int n); //costruttore con argomento numero di elementi vettore(vettore& v); // costruttore copia inte& operator[](int i); //accesso all'elemento i-esimo vettore operator+(vettore& v); //somma di 2 vettori;overloading di + vettore operator-(vettore& v); //sottrazione di 2 vettori;overloading di - inte operator*(vettore& v); //prodotto scalare;overloading di * inte operator|(vettore& v); //calcolo del modulo del vettore;overloading di | vettore molt_per_matrice(vettore& v,matrix& mat); //moltiplicazione di 1 vettore per una matrice void errore(char c[]); //segnala l'errore e esci dal programma void scrivi(char *s1); //visualizza il vettore };//vettore

162 162 matrix matrix::operator+(matrix& mat) //somma di matrici con overloading { matrix loc(mat); //crea una copia locale di matrice if(mat.r!=r) //se il numero delle righe delle 2 matrici non coincide { mat.errore("matrici con numero di righe incompatibili"); //messaggio di errore }//if if(mat.c!=c) //se il numero delle colonne delle 2 matrici non coincide { mat.errore("matrici con numero di colonne incompatibili"); //messaggio di errore }//if for(int i=0;i

163 163 matrix matrix::operator*(matrix& mat) //moltiplica 2 matrici;overloading di * { matrix loc(mat); //crea una copia locale di matrice if(c!=mat.r) //se il numero di colonne della prima é diverso dal { //numero di righe della seconda mat.errore("Errore!Matrici incompatibili per il prodotto"); //messaggio di errore }//if for(int i=0;i

164 164 vettore::vettore(int n) //costruttore di vettore a n elementi { size=n; //assegna il numero di elementi p=new inte[n]; //crea un vettore di n elementi }// costruttore inte& vettore::operator[](int i) //accesso all'i-esimo elemento del vettore;overloading di [] { if((i =size)) //se l'indice è sbagliato { cout << "L'indice del vettore é errato!"; //messaggio di errore }//if return (p[i]); //restituisci l'elemento i-esimo }//operator[] vettore vettore::operator+(vettore& v) //somma 2 vettori;overloading di + { vettore loc(v); //crea una copia locale del vettore in entrata if(v.size != size) //se il numero di elementi dei 2 vettori non coincide { v.errore("I vettori sono incompatibili e non si possono sommare"); //messaggio di errore }//if for(int i=0; i

165 165 inte vettore::operator*(vettore& v) //prodotto scalare dei vettori;overloading di * { if(v.size!=size) //se il numero di elementi dei 2 vettori non coincide { v.errore("I due vettori sono incompatibili e non si possono moltiplicare"); //messaggio di errore }//if inte s=0; //inizializza e azzera il valore del prodotto scalare for(int i=0;i

166 166 void main() //esempio di main { //definizione variabili vettore v1(d),v2(d); //costruisce 2 vettori di dimensione d //leggi i valori dei vettori cin >> v1[i]; //inserisco i valori degli elementi del primo vettore da tastiera cin >> v2[i]; //inserisco i valori degli elementi del secondo vettore da tastiera // v1=v1+v2; //somma i 2 vettori // v1=v1-v2; //sottrai i 2 vettori // dato=v1*v2; //moltiplica i 2 vettori // dato=v1|v1; //calcola il modulo del primo vettore // matrix m1(h,k); //crea l'oggetto matrice m1 //leggi i valori della matrice cin >> m1.accedi(i,j); //assegna i valori consecutivi a m1 // matrix m2(a,b); //crea l'oggetto matrice m2 //leggi i valori cin >> m2.accedi(i,j); //assegna i valori consecutivi a m2 // m1=m1+m2; //somma m1 con m2,assegna il risultato a m1 // m1=m1-m2; //sottrai m2 a m1,assegna il risultato a m1 // m1=m1*m2; //moltiplica m1 con m2,assegna il risultato a m1 // v1=v1.molt_per_matrice(v1,m1); //moltiplica v1 per m1,assegna il risultato // matrice_quad t(h,h,0,0),t1(h,h,0,0); //costruisci 2 matrici quadrate //leggi i valori cin >> t.accedi(i,j); //inserisci i valori della prima cin >> t1.accedi(i,j); //inserisci i valori della seconda }//main

167 167 scrivi il numero di elementi dei vettori:3 scrivi i valori del primo vettore:1 2 3 scrivi i valori del secondo vettore:4 5 6 il vettore v1: il vettore v2: dopo la somma v1 modificato=v1+v2 il vettore v1: dopo la differenza v1 modificato=v1-v2 il vettore v1: Il prodotto scalare di v1 vale 32 Il modulo di v1 é:3 Scrivi rispettivamente il numero di righe e di colonne della prima matrice:3 3 scrivi i valori della prima matrice: la matrice m1: Scrivi rispettivamente il numero di righe e di colonne della seconda matrice:3 3 scrivi i valori della seconda matrice: la matrice m2: dopo la somma m1 modificata=m1+m2 la matrice m1: Esempio di utilizzo


Scaricare ppt "1 Introduzione alla programmazione ad oggetti E.Mumolo, DEEI"

Presentazioni simili


Annunci Google