Corso di Programmazione Orientata agli oggetti Lezione Introduttiva a.a. 2012/2013 Francesco Fontanella
Docente Francesco Fontanella E-mail: fontanella@unicas.it Web: www.docente.unicas.it/francesco_fontanella Tel: 0776 2993382 Ricevimento: giovedì dalle 11.00 alle 13.00 (presso il mio studio) a.a. 2012/2013 2
Sito Web del Corso http://www.docente.unicas.it/francesco_fontanella/didattica/programmazione-orientata-agli-oggetti a.a. 2012/2013 3
Organizzazione del Corso ed Esame Lezione di teoria: Martedì dalle 9 alle 11 ( aula 1N.1) Esercitazioni Giovedì dalle 14 alle 17 (aula 1N.1 oppure 1.4) L'esame prevede: Prova pratica al calcolatore; Prova orale (con esercizi scritti); a.a. 2012/2013 4
Materiale Didattico Libro di testo: Fondamenti di programmazione in C++ di L. J. Aguilar, McGraw-Hill Italia. Materiale fornito dal docente (slides delle lezioni) e alcune dispense. Alcuni link utili: Documentazione linguaggio C e C++: http://www.cplusplus.com/ Corso C++ del CNR http://www.bo.cnr.it/corsi-di-informatica/corsocstandard/lezioni/01indice.html a.a. 2012/2013 5
Ambiente di Sviluppo L'ambiente utilizzato è NetBeans, ambiente free prodotto da Sun Microsystem. I file e le istruzioni per l'installazione sono disponibili sul sito del prof. Tortorella. a.a. 2012/2013 6
Programma del Corso Richiami del linguaggio C++; La ricorsione; Il sistema di I/O del C++; Programmazione orientata agli oggetti; a.a. 2012/2013 7
Programmazione Orientata agli oggetti È un paradigma di programmazione che definisce oggetti software Gli oggetti interagiscono tra loro per mezzo dello scambio di messaggi Viene usata per modellare sistemi complessi (Es. Simulatori, interfacce grafiche, ecc. ) Vantaggi: Migliora la gestione e la manutenzione Modularità e riuso del codice a.a. 2012/2013 8
Esempio Siano assegnati in ingresso i riempimenti n1 ed n2 ed i valori degli elementi di due vettori di reali V1 e V2. Si scriva un programma che calcoli le medie m1 ed m2 degli elementi di V1 e V2. Quindi, se m1 <= m2, copi in un vettore V3 i valori di V1 < m1, mentre se m1 > m2 copi in V3 i valori di V2 < m2. Infine, si stampino i valori delle medie calcolate ed il vettore V3 finale a.a. 2012/2013 9
Esempio: il main #include <iostream> #include <stdlib.h> using namespace std; void input (int& n,float v[]); void media (float& m,int& n,float v[]); void copia_in_vettore(int& n,float v[],float& m,float v3[],int& num); void output (int num, float v3[]); int main (){ int n1,n2,n3; n3=0; float V1[100],V2[100],V3[100],m1,m2; m1=0;m2=0; // INPUT input(n1,v1); input(n2,v2); a.a. 2012/2013 10
Esempio: il main // Calcolo delle medie m1 = media(n1,v1); m = media(n2,v2); // Verifica delle condizioni if (m1<m2) copia_in_vettore(n1,v1,m1,v3,dim); else copia_in_vettore(n2,v2,m2,v3,dim); // OUTPUT cout<<"la media del primo vettore e': "<<m1<<endl; cout<<"la media del secondo vettore e' : "<<m2<<endl; cout<<"il vettore V3 è:"<<endl; output(n3,v3); } system("pause"); return 0; a.a. 2012/2013 11
La funzione per il calcolo della media float media(int n, float v[]){ float s=0; for (int i=; i<n; i++) s+=v[i]; } return s / n; a.a. 2012/2013 12
La funzione di Copia void copia_minori (int n_in,float v_in[], float m, float v_out[],int &n_out){ } int j=0; for (int i=0;i<n_in;i++) if (v_in[i]<m){ } v_out[j]=v[i]; j++; n_out = j; a.a. 2012/2013 13
Esercizio Siano dati in ingresso, da file o da tastiera, i riempimenti n1, n2, n3 ed i valori di tre vettori V1, V2 e V3 di interi. Si scriva un programma che elimini da V1 gli elementi il cui valore è maggiore del massimo valore in V2 e quindi da V2 gli elementi il cui valore è maggiore del massimo valore in V3. Si forniscano in uscita i vettori V1 e V2 residui e, per ognuno, il valore del massimo usato come confronto. I risultati devono essere accompagnati da commenti esplicativi. NOTA Per l'eliminazione dal vettore degli elementi di valore val usare la funzione: void elimina(int &n,int v[], int val) { int i, k; k=0; for(i=0;i<riemp;i++) if(v[i]>val) a.a. 2012/2013 14
Soluzione dell'esercizio: main #include <iostream> #include <stdlib.h> using namespace std; void input (int& n,float v[]); void elimina (float& m,int& n,float v[]); int ric_max(int n,float v[]); void output (int num, float v3[]); int main (){ int n1,n2,n3; float V1[100],V2[100],V3[100],m2,m3; // INPUT input(n1,v1); input(n2,v2); input(n3,v3); a.a. 2012/2013 15
Soluzione dell'esercizio: main // Calcolo delle massimi m2 = ric_max(n2,v2); m3 = ric_max(n3,v3); // Eliminazione dai vettori elimina(n1, V1, m2); elimina(n2, V2, m3); // OUTPUT cout<<"il massimo del vettore 2 e': "<<m2<<endl; cout<<"il massimo del vettore 3 e': "<<m3<<endl; cout<<"il vettore 1 residuo è: "<<endl; output(n1,v1); cout<<"il vettore 2 residuo è: "<<endl; output(n2,v2;) system("pause"); } return 0; a.a. 2012/2013 16
La Ricorsione a.a. 2012/2013 17
La ricorsione Si dice che un oggetto (una struttura dati, una funzione matematica, un concetto ) è ricorsivo se è possibile darne una definizione in termini di (varianti di) sè stesso Esempio: la funzione matematica fattoriale n!=n*(n-1)! Se n 1 0!=1 Esempio: la definizione di sequenza Una sequenza è la sequenza vuota oppure è un elemento seguito da una sequenza: s x 1 U s s x 2 U s s x 3 U s.. s n <> a.a. 2012/2013 18
La ricorsione Esempio: una filastrocca per bambini C'era una volta un re seduto sul sofà che disse alla sua serva raccontami una storia e la serva incominciò: C'era una volta un re... Esempio: in natura a.a. 2012/2013 19
Il Principio dell'induzione Il principio d'induzione è un enunciato sui numeri naturali che in matematica trova un ampio impiego nelle dimostrazioni: In pratica: si dimostra che vale P(1) (o P(0)), cioè che la proprietà P vale per 1(o 0). si assume come ipotesi che l'asserto P(n) valga per un generico n e da tale assunzione si dimostra che vale anche P(n + 1) a.a. 2012/2013 20
Il Principio dell'induzione: un Esempio Dimostriamo che vale l'asserto: n N Vogliamo quindi dimostrare la seguente proprietà P Base dell'induzione: l'asserto è vero per n=1: Passo induttivo: 1 2 3 n= n n 1 2 P n =1 2 3 n= n n 1 2 a.a. 2012/2013 21
Il Principio dell'induzione: un Esempio Passo induttivo: P n = n n 1 2 P n 1 = n 1 n 1 1 2 Possiamo facilmente asserire che P n 1 =1 2 3 n n 1 =P n n 1 Da ciò, inpochi passi è facile dmostrare l'asserto: P n 1 = n n 1 n 1 = n 1 n 1 1 2 2 a.a. 2012/2013 22
La Ricorsione In programmazione la ricorsione è una tecnica potente che: permette di suddividere un problema da risolvere in sottoproblemi simili a quello originale la potenza della ricorsione nasce dalla possibilità di definire un insieme infinito di oggetti con regola finita allo stesso modo, un insieme infinito di computazioni può essere descritto con un programma ricorsivo finito. La ricorsione si applica ad algoritmi ricorsivi (i quali a loro volta sono spesso basati su strutture dati ricorsive) Per tali algoritmi la tecnica ricorsiva permette di scrivere programmi eleganti e sintetici, sarà tuttavia opportuno verificarne di volta in volta l'efficienza rispetto ad altri tipi di soluzioni a.a. 2012/2013 23
Il programma fattoriale La versione ricorsiva del fattoriale è: int fatt(int x){ int f; if (x<=1) f=1; else f=x*fatt(x 1); return f; } passo BASE Passo INDUTTIVO Mentre quella iterativa è: int fatt(const int x){ int f=1,i; for(i=1;i<=x;i++) f=f*i; return f; } a.a. 2012/2013 24
Lo schema degli algoritmi ricorsivi Un algoritmo ricorsivo è sempre codificato per mezzo di un programma che richiama se stesso: P (T1 x) {... if (p(x)) F; else C(S,P); R } int fatt(int x){ int f; if (x<=1) f=1; else f=x*fatt(x 1); return f; } Il predicato p(x) verifica il caso BASE a.a. 2012/2013 25
Terminazione La chiamata ricorsiva deve quindi essere subordinata ad una condizione che ad un certo istante risulti soddisfatta (il predicato p). Il numero di chiamate necessarie viene detto profondità della ricorsione a.a. 2012/2013 26
Algoritmi ricorsivi Esistono diversi tipi di algoritmi ricorsivi: Si parla di mutua ricorsione quando nell'algoritmo una funzione ne richiama un'altra che a sua volta richiama la prima, altrimenti si parla di ricorsione diretta Si parla di ricorsione lineare quando vi è solo una chiamata ricorsiva all'interno della funzione, e di ricorsione non lineare nel caso in cui le chiamate ricorsive siano più di una. La distinzione più importante ai fini pratici si ha fra ricorsione di coda (tail recursion) e ricorsione non di coda. Si parla di ricorsione di coda quando la chiamata ricorsiva è l'ultima istruzione eseguita nella funzione. Questo tipo di algoritmo ricorsivo è possibile trasformarlo semplicemente in una versione iterativa, che di solito è più efficiente, a.a. 2012/2013 27
Meccanismo interno di ricorsione Un sottoprogramma ricorsivo è dunque un sottoprogramma che richiama direttamente o indirettamente se stesso Non tutti i linguaggi realizzano il meccanismo della ricorsione. Quelli che lo realizzano possono utilizzare due tecniche: gestione LIFO di più copie della stessa funzione, ciascuna con il proprio insieme di variabili locali Gestione mediante record di attivazione; un unica copia del codice del sottoprogramma ma ad ogni chiamata è associato un record di attivazione (variabili locali e punto di ritorno). In questo caso diversi record di attivazione dello stesso sottoprogramma possono essere contemporaneamente presenti nello stack a.a. 2012/2013 28
Schema ricorsivo Fase ascendente Fase discendente fatt(3) fatt(2) fatt(1) main........fatt(3) if (x<=1) f=1; else f=x*fatt(x-1); if (x<=1) f=1; else f=x*fatt(x-1); if (x<=1) f=1; else f=x*fatt(x-1); 6 return f; 2 return f; 1 return f; a.a. 2012/2013
Dalla forma ricorsiva a quella iterativa Un problema ricorsivo può sempre essere risolto in termini iterativi (il viceversa non è vero). Nel caso in cui la ricorsione è in coda, la trasformazione è molto semplice. Ad esempio: P (T1 x) {... if p(x) F; else {S;P(x);} return } while!p(x) S; F; Quando invece la ricorsione non è l'ultima istruzione della procedura si può optare per una soluzione che preveda l'utilizzo di uno stack di supporto che permette di salvare i valori delle chiamate ricorsive e tramite un ciclo while simulare ciò che fa lo stack di sistema. a.a. 2012/2013
Dalla forma ricorsiva a quella iterativa: il fattoriale Forma ricorsiva Forma iterativa int fatt(const int x){ int f; if (x<=1) f=1; else f=x*fatt(x-1); return f; } int fatt(const int x){ int f=1,i; for(i=1;i<=x;i++) f=f*i; return f; } a.a. 2012/2013
Esponenziale float exp( float x, int n) { if (n == 1) return x; else return x*exp(n 1); } ricorsione in coda NOTA Questa versione tiene conto solo di esponenti positivi. Provare a scrivere la stessa funzione (ricorsiva) tenendo conto anche del caso n < 0 a.a. 2012/2013
Calcolo Lunghezza di una Stringa void strlen( char *str) { if (str[0] == '\0') return 0; else return 1 + strlen(&str[1]); } Posso anche scrivere: *str == '\0' ricorsione in coda a.a. 2012/2013