Programmazione Object Oriented in C#

2,214 views

Published on

Quarta lezione del corso di introduzione a C# ed all'ambiente .NET tenuto presso ENAIP FVG di Udine.
Oggetti, ereditarietà e polimorfismo, con esempi ed esercizi. Dai TDA agli oggetti, un percorso dalla programmazione strutturata alla potenza della programmazione OO.

Un ringraziamento particolare a Stefano Mizzaro e Paolo Coppola

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,214
On SlideShare
0
From Embeds
0
Number of Embeds
462
Actions
Shares
0
Downloads
0
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Programmazione Object Oriented in C#

  1. 1. + Lezione 4 – Introduzione a .NET Dr. Paolo Casoto, Ph.D - 2012
  2. 2. + Credits I lucidi di questa lezione sono stati redatti dal Dr. Paolo Casoto nel 2012. Sono rilasciati con licenza Creative Commons Attribuzione, non commerciale e non opere derivate. Dr. Paolo Casoto, Ph.D - 2012
  3. 3. + Visibilità (scope) for (int i = 1; i <= 10; i++) { ... }  i visibile solo nel corpo del forclass Prova { public static void Main (String[] args) { int j = 6; for (int i = 1; i <= 5; i++) { Console.WriteLine(i); Console.WriteLine(j); } Secondo voi il tutto Console.WriteLine(i); compila ? Console.WriteLine(j); } Fate attenzione alla} variabile i Dr. Paolo Casoto, Ph.D - 2012
  4. 4. + Regola di visibilità  Una variabile è visibile unicamente:  all’interno del blocco in cui è dichiarata  nei blocchi annidati all’interno del blocco di dichiarazione.  anche se utilizzata come parametro formale !!! class Visibilita { static void F (int i) { // Qui i e visibilae, j no } static void G (int j) { // Qui j e visibile, i no } public static void Main (String[] args) { // Qui non sono visibili ne i ne j } } Dr. Paolo Casoto, Ph.D - 2012
  5. 5. + Blocco  Da “{” a “}”  Di solito: programma; metodo; ciclo for  Ma non è detto, come nell’esempio seguente  Vi ricordate la definizione dei blocchi per i salti class Prova { public static void Main(String[] args) { int a; { int b; Secondo voi il tutto { int c; compila ? } Console.WriteLine(b); Console.WriteLine(c); } } } Dr. Paolo Casoto, Ph.D - 2012
  6. 6. + Variabili con nomi uguali  Variabili con nomi uguali possono coesistere purché in blocchi diversiclass Visibilita { static void F (int i) { int j; ... } static void G (int j) { int i; ... } public static void Main (String[] args) { int j; ... }} Dr. Paolo Casoto, Ph.D - 2012
  7. 7. + Variabili all’esterno dei metodi  Variabili locali a un metodo  Variabili di classe (globali)class Visibilita { Variabili di classe static int x,y; static void F (int i) { ... } static int G (int j) { ... } public static void Main (String[] args) { double j; ... }} Dr. Paolo Casoto, Ph.D - 2012
  8. 8. + Modello a contorni  Le variabili possono quindi essere definite come: 1. locali a un metodo (parametri formali) 2. di classe 3. definite in un blocco (e.g.: all’interno di un ciclo for quale variabile utilizzata dalla condizione di controllo)  Variabili possono avere nomi uguali nel rispetto delle condizioni sopra citate.  Modello a contorni  Utile per capire dove una variabile è visibile  Un “contorno” (rettangolo) intorno a ogni blocco Dr. Paolo Casoto, Ph.D - 2012
  9. 9. + Modello a contorni: esempioclass Visibilita { static int i1; static void F (int i2) { // int i2; sarebbe lo stesso ... for (int i3 ...) { ... if (...) { int i4; ... } } } public static void Main (String[] args) { int j; ... }} Dr. Paolo Casoto, Ph.D - 2012
  10. 10. + Blocchi annidati  Variabili usate in un blocco ma definite in un blocco esterno:  Nessun problema, dopotutto il blocco interno è dentro al blocco esterno!  Variabili con stesso nome in blocchi annidati  2 casi:  Locale al metodo e di classe  Quella locale nasconde quella di classe  All’interno di un blocco e locale al metodo  Errore, conflitto di nomi Dr. Paolo Casoto, Ph.D - 2012
  11. 11. + Esempio caso 1class Nascoste { static int x,y; //Def. var. globali static void F() { int x; x = 1; // Locale y = 1; // Globale Console.WriteLine(x); Console.WriteLine(y); } public static void Main (String[] args) { x = 0; // Globale y = 0; // Globale Cosa stampa questo F(); programma ? Console.WriteLine(x); Console.WriteLine(y); }} Dr. Paolo Casoto, Ph.D - 2012
  12. 12. + Esempio caso 2 class VariabiliBlocchi { public static void Main (String[] args) { int x = 0; if (x > 0) { Secondo voi il tutto int x = 1; compila ? x++; } } } Dr. Paolo Casoto, Ph.D - 2012
  13. 13. + Variabili “globali” vs. passaggio parametri  Usate parametri, non variabili globali  È più semplice capire cosa fa un metodo:  basta leggere il metodo  non bisogna far riferimento a tutto il resto del programma  (nello specifico alle variabili globali ed agli altri metodi) Dr. Paolo Casoto, Ph.D - 2012
  14. 14. + Esempioclass Parametri { static int x; Per capire cosa fa Inc static void Inc() { devo leggere tutto il x++; programma } public static void Main (String[] args) { x = 0; Inc(); Console.WriteLine(x); QUESTO METODO E’ } ORRIBILE !!!} Dr. Paolo Casoto, Ph.D - 2012
  15. 15. + Esercizio: traccia di esecuzione class EsercizioScope1 { static int x, y; static int Metodo1(int x) { x = 1; y = 1; Console.WriteLine(“Metodo1 " + x + " " +y); return x + y; } static void Metodo2() { int y; x = 2; y = Metodo1(x); Console.WriteLine(“Metodo2 " + x + " " +y); } public static void Main (String[] args) { x = 0; y = 0; Metodo2(); Console.WriteLine(“Main " + x + " " + y); } } Dr. Paolo Casoto, Ph.D - 2012
  16. 16. + La durata (lifetime)  Da quando la memoria viene allocata a quando viene “cancellata”  Diverso da visibilità:  Ad un dato momento dell’esecuzione, una variabile può esistere e non essere visibile  (se una variabile non esiste, non può essere visibile…) Dr. Paolo Casoto, Ph.D - 2012
  17. 17. + Esempio  Durante l’esecuzione di g, i esiste ma non è visibile class Automatiche { static void F() { int i; G(); ...; } static void G() { ... } public static void Main (String[] args) { F(); } } Dr. Paolo Casoto, Ph.D - 2012
  18. 18. + Visibilità e durata  La visibilità è un concetto statico  Si guarda il codice, ci si aiuta con il modello a contorni  La durata è un concetto dinamico  Bisogna eseguire il programma  P.S. Variabili di classe:  In un record di attivazione in fondo alla pila  Allocato a inizio esecuzione  Durata = tutta l’esecuzione Dr. Paolo Casoto, Ph.D - 2012
  19. 19. + Esercizioclass ... { static void F() { int x; G(); ...; } static void G() { ...; } public static void Main (String[] args) { ...; F(); G(); }} La variabile x esiste durante l’esecuzione di g? Dr. Paolo Casoto, Ph.D - 2012
  20. 20. + Metodi sovraccarichi  Firma di un metodo =  nome + elenco dei (tipi dei) parametri  Attenzione: non il tipo restituito!  “Sovraccarico” (overload):  Metodi con nome uguale e firma diversa  Il nome del metodo è carico di più significati  Il C# distingue i metodi sulla base della loro firma Dr. Paolo Casoto, Ph.D - 2012
  21. 21. + Esempioclass Overloading { static int Somma (int x, int y) { return x + y; } static int Somma (int x, int y, int z) { return x + y + z; } public static void Main (String[] args) { Console.WriteLine(Somma(1,1)); Console.WriteLine(Somma(1,2,3)); }} static double Somma (int x, int y) { return (double) x + y; } Dr. Paolo Casoto, Ph.D - 2012
  22. 22. + Parametri di tipo array  Sintassi simile ai tipi predefiniti  anche per il tipo dei valori restituiti  Differenze  Se si modifica un array in un metodo, non viene modificato solo il parametro formale ma anche il parametro attuale!  Passaggio “per riferimento” (in realtà è per valore e viene passato per valore il riferimento) Dr. Paolo Casoto, Ph.D - 2012
  23. 23. + Esempioclass StampaMatrice { static void StampaM(int[][] m) { for (int i = 0; i < m.Length; i++) { for (int j = 0; j < m[i].Length; j++) Console.Write(m[i][j] + "t"); Console.WriteLine(); } } public static void Main (String[] args) { int[][] matrice = { {12, 23, 23, 5678}, {987, 87 , 3, 0}, {12354,34,2,0}}; StampaM(matrice); }} Dr. Paolo Casoto, Ph.D - 2012
  24. 24. + Esempioclass ParametriArray1 { static void M(int[] a) { for (int i = 0; i < a.Length; i++) a[i] = 0; } public static void Main (String[] args) { int[] vettore = { 1, 2, 3 }; for (int i = 0; i < vettore.Length; i++) Console.WriteLine(vettore[i]); M(vettore); for (int i = 0; i < vettore.Length; i++) Console.WriteLine(vettore[i]); }} 1, 2, 3, 0, 0, 0 Dr. Paolo Casoto, Ph.D - 2012
  25. 25. + Perché  Passaggio per (valore del) riferimento  Le variabili e i parametri di tipo primitivo stanno sulla pila dei record di attivazione  Gli array no, stanno sullo heap  Zona di memoria separata dalla pila e gestita in modo più “disordinato”  Sullo stack ci stanno  I valori delle variabili di tipo primitivo  I riferimenti agli array  Riferimento ~ indirizzo in memoria Dr. Paolo Casoto, Ph.D - 2012
  26. 26. + Perché Dr. Paolo Casoto, Ph.D - 2012
  27. 27. + Perché Dr. Paolo Casoto, Ph.D - 2012
  28. 28. + Esempio rivistoclass ParametriArray1 { static void M(int[] a, int b) { for (int i = 0; i < a.Length; i++) a[i] = 0; b = 0; } public static void Main (String[] args) { int[] vettore = { 1, 2, 3 }; int x = 4; for (int i = 0; i < vettore.Length; i++) Console.WriteLine(vettore[i]); Console.WriteLine(x); M(vettore, x); for (int i = 0; i < vettore.Length; i++) Console.WriteLine(vettore[i]); Console.WriteLine(x); }} Dr. Paolo Casoto, Ph.D - 2012 1, 2, 3, 4, 0, 0, 0, 4
  29. 29. + E gli array di array?  Un array è un array  Un tipo primitivo è un tipo primitivo  Ergo, se l’elemento di un array è:  di un tipo primitivo, viene passato per valore  di tipo array, viene passato per (valore il) riferimento  Esercizio  Scrivere un metodo void stampaM(int[][] m) che:  visualizza la matrice m;  invoca un metodo void azzera(int [] a) per azzerare il vettore in m[0] Dr. Paolo Casoto, Ph.D - 2012
  30. 30. + Quindi, riassumendo  I parametri di tipo predefinito (byte, short, int, long, float, double, char, boolean) vengono passati per valore  Le modifiche non si ripercuotono sul parametro attuale  I parametri di tipo array sono passati “per riferimento” (o meglio, il loro riferimento è passato per valore)  Modifiche su parametro formale • modifiche su parametro attuale  (anche gli oggetti, di cui parleremo…) Dr. Paolo Casoto, Ph.D - 2012
  31. 31. + TDA  Tipo di Dato Astratto (TDA)  Abstract Data Type (ADT)  I metodi (procedure e funzioni) possono essere visti come un modo per estendere il linguaggio di programmazione  appena definito un nuovo metodo, è come se il linguaggio avesse una nuova istruzione  È un meccanismo di astrazione: astraggo dai dettagli pensando al livello delle nuove istruzioni  Ne esiste un altro...  Migliore (vedremo perché) Dr. Paolo Casoto, Ph.D - 2012
  32. 32. + Struttura programma C#? class ... { static <tipo> <id> (<parametri>) { ... } static <tipo> <id> (<parametri>) { ... } public static void Main (String[] args) { ... } static <tipo> <id> (<parametri>) { ... } static <tipo> <id> (<parametri>) { ... } } Dr. Paolo Casoto, Ph.D - 2012
  33. 33. + Un altro meccanismo di astrazione: i TDA  Possiamo estendere il linguaggio definendo nuovi tipi di dato  Per farlo bisogna:  definire “come sono fatti”  decidere quali operazioni sono lecite su di essi  (Tipo = valori + operazioni)  Per definire un nuovo tipo di dato si deve specificare una classe  il nome della classe rappresenterà il nuovo tipo  una classe definisce le sue variabili e i suoi metodi Dr. Paolo Casoto, Ph.D - 2012
  34. 34. + Definire TDA: la sintassi public class <NomeDelTDA> { <tipo1> <var1>; <tipo2> <var2>; … public static <tipoMetodo1> <NomeMetodo1>(<parametri1>) { } public static <tipoMetodo2> <NomeMetodo2>(<parametri2>) { } ... } Dr. Paolo Casoto, Ph.D - 2012
  35. 35. + Esempio 1: classe coordinate  Definire un nuovo tipo che public class Coordinate rappresenta le coordinate di un punto del piano cartesiano {  Decidiamo il nome della public int x; classe: Coordinate public int y;  Decidiamo quali } informazioni/dati saranno oppure presenti nella classe: x, y public class Coordinate { public double x; public double y; } Dr. Paolo Casoto, Ph.D - 2012
  36. 36. + Esempio 2: classe ora Definire un nuovo tipo che public class Ora { rappresenta un’ora del giorno public int ore;  Decidiamo il nome della classe: public int minuti; Ora public int secondi;  Decidiamo quali informazioni/dati saranno presenti nella classe: }  ore, minuti, secondi  oppure oppure  secondi trascorsi dalla public class Ora { mezzanotte public int secondi; } Dr. Paolo Casoto, Ph.D - 2012
  37. 37. + Esempio 3: classe freccia orizzontale Definire un nuovo public class FrecciaOrizzontale tipo che rappresenta una freccia { orizzontale public int lunghezza;  Decidiamo il nome public char verso; della classe: } FrecciaOrizzontale oppure  Decidiamo quali informazioni/dati saranno presenti public class FrecciaOrizzontale nella classe: lunghezza, verso { public int lunghezza; public boolean versoDestra; } Dr. Paolo Casoto, Ph.D - 2012
  38. 38. + Usare TDA  Una volta definita una classe abbiamo un nuovo tipo  (non abbiamo scritto un programma; non c’è un Main)  e possiamo usarlo!  Ora si possono:  dichiarare variabili di quella classe (di quel tipo)  creare nuovi valori (istanze)  usare le variabili  (in un’altra classe/file… ad es. nel metodo Main… vedremo) Dr. Paolo Casoto, Ph.D - 2012
  39. 39. + Dichiarazione  Analogamente a come si dichiarano le variabili con tipo primitivo:  int x, k, count;  Coordinate punto, coppia, pluto;  Ora oraDelGiorno, pippo;  Dichiarare una variabile non basta. Per usare un TDA bisogna creare esplicitamente un valore  Bisogna allocare dello spazio in memoria  Lo spazio per i tipi primitivi invece viene allocato in modo automatico Dr. Paolo Casoto, Ph.D - 2012
  40. 40. + L’istruzione new  Dichiarazione e istanziazione/allocazione:  Coordinate punto;  punto = new Coordinate();  oppure, in una sola riga:  Coordinate punto = new Coordinate();  new  Alloca lo spazio nello heap per una nuova istanza  Viene creato un nuovo oggetto (che verrà riferito dalla variabile)  Vi ricorda qualcosa? Dr. Paolo Casoto, Ph.D - 2012
  41. 41. + Istanziazione/allocazione Dichiarazione: Istanziazione: Coordinate punto; punto = new Coordinate(); punto x ... yPila dei record di attivazione Heap Dr. Paolo Casoto, Ph.D - 2012
  42. 42. + La notazione puntata  Una volta dichiarata una variabile e istanziato un TDA, si può accedere ai suoi attributi, ovvero alle variabili, usando questa sintassi:  variabileTDA.variabileComponente  I metodi dei TDA invece si invocano premettendo il nome della classe:  TDA.Metodo(parametri)  Esempi  punto.x = 2;  punto.y = 3 + punto.x;  Console.WriteLine(punto.y); Dr. Paolo Casoto, Ph.D - 2012
  43. 43. + Esempio 2  Scrivere un programma che legge da tastiera un’ora del giorno e la stampa...Ora x = new Ora();//Legge un’ora del giornox.ore = Int32.Parse(Console.ReadLine());x.minuti = Int32.Parse(Console.ReadLine());x.secondi = Int32.Parse(Console.ReadLine());Console.WriteLine(”Sono le ”+x.ore+”:”+x.minuti+”.”+x.secondi);... Dr. Paolo Casoto, Ph.D - 2012
  44. 44. + Esempio 2  Con l’altra definizione della classe Ora...Ora x = new Ora();//Legge un’ora del giornoint ore = Int32.Parse(Console.ReadLine());int minuti = Int32.Parse(Console.ReadLine());int secondi = Int32.Parse(Console.ReadLine());x.secondi = ore*3600+minuti*60+secondi;Console.WriteLine(”Ora sono le “+(x.secondi/3600)+”:” +((x.secondi%3600)/60)+”.” +(x.secondi%60));... Dr. Paolo Casoto, Ph.D - 2012
  45. 45. + Esempio 3  Scrivere un programma che legge da tastiera la lunghezza e il verso di una freccia e poi la stampa ... FrecciaOrizzontale x = new FrecciaOrizzontale(); //Legge lunghezza e verso x.lunghezza = Int32.Parse(Console.ReadLine()); x.verso = Char.Parse(Console.ReadLine()); if (x.verso == ‘s’) Console.Write(”<”); for (int i=0; i<x.lunghezza; i++) Console.Write(”-”); if (x.verso == ‘d’) Console.WriteLine(”>”); else Console.WriteLine(); ... Dr. Paolo Casoto, Ph.D - 2012
  46. 46. + Esempio 3 ... FrecciaOrizzontale x = new FrecciaOrizzontale(); //Legge lunghezza e verso x.lunghezza = Int32.Parse(Console.ReadLine()); char verso = Char.Parse(Console.ReadLine()); x.versoDestra = (verso == ‘d’); if (!x.versoDestra) Console.Write(”<”); Oppure, con l’altra definizione for (int i=0; i<x.lunghezza; i++) della classe FrecciaOrizzontale Console.Write(”-”); if (x.versoDestra) Console.Write(”>”); Console.WriteLine(); ... Dr. Paolo Casoto, Ph.D - 2012
  47. 47. + L’occultamento delle informazioni (1/2)  Negli esempi precedenti non è evidente il vantaggio di usare i TDA  L’astrazione è ancora limitata  Per usare un TDA si fa riferimento direttamente a come è fatto (alla sua implementazione)  Mancano le operazioni del tipo  Negli esempi:  cambio definizione della classe => cambiare anche il codice che usa quei TDA Dr. Paolo Casoto, Ph.D - 2012
  48. 48. + L’occultamento delle informazioni (2/2)  Due aspetti:  Bisogna nascondere l’implementazione dei TDA  L’accesso e la modifica delle variabili interne avviene solo tramite metodi (le operazioni del tipo)  In questo modo si realizza un’astrazione maggiore:  chi userà la classe dovrà conoscere solo l’insieme dei metodi (la sua interfaccia)  non “come è fatto dentro” (l’implementazione)  Tipo di dato astratto: si astrae dall’implementazione (quando si usa) Dr. Paolo Casoto, Ph.D - 2012
  49. 49. + I modificatori  In C# (così come in Java) si possono nascondere le variabili di una classe usando il modificatore private  Esempio:  public class Coordinate {  private int x;  private int y;  } Dr. Paolo Casoto, Ph.D - 2012
  50. 50. + Variabili private  Se una variabile è dichiarata privata, può essere riferita solo nei metodi della sua classe  Non è visibile al di fuori della classe  Se un metodo di un’altra classe prova ad accedere ad una variabile privata, il compilatore segnala un errore  Se si nascondono le variabili di una classe, si devono aggiungere dei metodi per modificarle  Le operazioni del tipo  In C# esiste un costrutto ad hoc per gestire l’accesso alle variabili private di un TDA  Le proprietà Dr. Paolo Casoto, Ph.D - 2012
  51. 51. + Esempio 1Stefano Mizzaro - TDA Dr. Paolo Casoto, Ph.D - 2012
  52. 52. + Esempio 2 Dr. Paolo Casoto, Ph.D - 2012
  53. 53. + Esempio 2: altra implementazione Dr. Paolo Casoto, Ph.D - 2012
  54. 54. + Le proprietà  Entità particolari: appaiono come attributi di un oggetto ma si comportano a tutti gli effetti come metodi  Corrispettivo in C# dei metodi getter e setter che trovate nei vari linguaggi di programmazione orientati agli oggetti  Ciascuna propietà può essere composta da due rami, il ramo get ed il ramo set.  La proprietà utilizza il ramo get quando è utilizzata nel lato destro di una espressione  Restituisce il valore della variabile associata alla proprietà  La proprietà utilizza il ramo set quando è utilizzata nel lato sinistro di una espressione di assegnamento  Imposta il valore della variabile associata alla proprietà Dr. Paolo Casoto, Ph.D - 2012
  55. 55. + Le proprietà  E’ possibile definire anche proprietà con un solo ramo  E.g.: definiamo il solo ramo get per le proprietà in sola lettura.  Consentono di definire la logica da eseguire a ciascuna modifica dei valori di un attributo.  Siete voi a decidere ed a nascondere al di fuori i particolari implementativi relativi alla semantica dei vostri parametri public class Cane { int peso; public int Peso{ get { return peso; } set { peso = value; } } } Dr. Paolo Casoto, Ph.D - 2012
  56. 56. + Le proprietà  E’ possibile associare una proprietà anche alle variabili di classe  Vi ricordate…quelle con il modificatore static. In questo caso anche la proprietà sarà caratterizzata dal modificatore static  Proprietà di classe  Anche nel caso delle proprietà possono essere utilizzati i modificatori per il polimorfismo dei metodi di istanza …  Lo scopriremo insieme la prossima lezione  virtual, abstract, override, sealed  Possono essere caratterizzate, sui due rami, da una diversa accessibilità  E.g.: ramo set private e ramo get public Dr. Paolo Casoto, Ph.D - 2012
  57. 57. + Le proprietà  Come generare automaticamente una proprietà ?  Selezionate una variabile e premete la combinazione Ctrl + R e successivamente E  O, in alternativa, con il tasto destro attivate il menù “Refactoring” e successivamente “Incapsula Campo”  Per default le proprietà possono avere definizione vuota  In tal caso non aggiungono nulla al comportamento classico dei metodi setter e getter public class Cane Implementa in { automatico un public int Peso{ attributo privato non get; set; accessibile } } Dr. Paolo Casoto, Ph.D - 2012
  58. 58. + TDA: l’idea  Tipo di Dato Astratto (TDA)  Abstract Data Type (ADT)  L’idea è:  Programma che gestisce numeri complessi => aggiungo il tipo di dato astratto NumeroComplesso  Programma dell’anagrafe => aggiungo i TDA Persona, Indirizzo, Data, …  …  Non “aggiungo al C#i metodi che non ha” ma “aggiungo al C# i tipi che non ha”  E poi li uso astraendo dall’implementazione  È un meccanismo di astrazione Dr. Paolo Casoto, Ph.D - 2012
  59. 59. + TDA: i concetti (1/2)  Astrazione: nuovo tipo (non nuova istruzione)  Definire  Come sono fatti (attributi): implementazione  Operazioni (metodi, per ora static): interfaccia  class  Usare  Dichiarazione  E allocazione, sullo heap  new (ricorda qualcosa?)  Notazione puntata (ricorda qcosa?)  Non solo per accedere alle componenti  Anche per invocare i metodi Dr. Paolo Casoto, Ph.D - 2012
  60. 60. + TDA: i concetti (2/2)  Occultamento delle informazioni (dell’implementazione)  Information (implementation) hiding  Cambio implementazione = cambio uso? NO!!  private  Operazioni di accesso con metodi  Astratto = si astrae dall’implementazione quando si usa  Limitazione alla libertà del programmatore? Sì, ma positiva!  Divide et impera (anche con i metodi)  Riuso (i TDA creati per un programma spesso funzionano anche per altri programmi; i metodi no) Dr. Paolo Casoto, Ph.D - 2012
  61. 61. + Esempio: definizione e usopublic class Ora { private int secondi; public static void ImpostaOra(Ora x, int o, int m, int s) { x.secondi = o*3600+m*60+s; } public static int GetOre(Ora x) {return x.secondi/3600;} public static int GetMinuti(Ora x) { return (x.secondi%3600)/60; } public static int GetSecondi(Ora x) {return x.secondi%60;}} class UsaOra { public static void Main(String[] args) { ... Ora h = new Ora(); Ora.ImpostaOra(h,12,22,31); Console.WriteLine("Sono le ore ” +Ora.GetOre(h)); ...}} Dr. Paolo Casoto, Ph.D - 2012
  62. 62. + Terminologia  Tipi  TDA  Classi  Variabili  (Valori, Istanze, Oggetti)  Attributi  Incapsulamento = unitarietà + inaccessibilità  Unitarietà:  “raggruppamento”  definizione in un unico punto  Inaccessibilità: dell’implementazione Dr. Paolo Casoto, Ph.D - 2012
  63. 63. + Il costruttore  Le classi hanno un metodo particolare, il costruttore, che viene invocato quando si istanzia un TDA  Essendo il primo metodo della classe che viene eseguito, di solito viene usato per inizializzare la variabile creata  Il costruttore è un metodo “strano”:  ha (deve avere) lo stesso nome della classe e  non ha un tipo restituito (nemmeno void)  viene invocato in modo strano (con la new) Dr. Paolo Casoto, Ph.D - 2012
  64. 64. + Esempio Dr. Paolo Casoto, Ph.D - 2012
  65. 65. + Costruttori Dr. Paolo Casoto, Ph.D - 2012
  66. 66. + Esempio: il TDA Ora public class Ora { private int ore, minuti, secondi; public Ora(int o, int m, int s) { ore = o; minuti = m; secondi = s; } public static void SetOra(Ora x, int o, int m, int s){ x.ore = o; x.minuti = m; x.secondi = s; } public static void SetOra(Ora x, int o, int m) { setOra(x,o,m,0); } public static int GetOre(Ora x) {return x.ore;} public static int GetMinuti(Ora x) {return x.minuti;} public static int GetSecondi(Ora x){return x.secondi;} } Dr. Paolo Casoto, Ph.D - 2012
  67. 67. + Esempio: uso del TDA Ora class UsaOra { public static void main(String[] args) { Ora x = new Ora(12,32,05); Ora y = new Ora(Ora.getOre(x), 20, 3); Console.WriteLine(Ora.getMinuti(y)); Ora.setOra(y, 20, 4); Console.WriteLine(Ora.getOre(y) + “:” + Ora.getMinuti(y) + “:” + Ora.getSecondi(y)); } } Dr. Paolo Casoto, Ph.D - 2012
  68. 68. + Esercizi  Che cosa fa il seguente costruttore?  Ora(int o) { ore = o; minuti = 0; secondi = 0; }  E questo?  Ora(Ora o) { ore = o.ore; minuti = o.minuti; secondi = o.secondi; } Dr. Paolo Casoto, Ph.D - 2012
  69. 69. + Il costruttore  Un costruttore può avere parametri di ogni tipo, anche della sua stessa classe  Può invocare altri metodi  Anche della stessa classe, ma attenzione!  Quando si deve creare un’istanza di una certa classe, si deve invocare uno dei suoi costruttori  Se non è stato specificato nessun costruttore  allora si può usare quello senza parametri (che c’è “automaticamente”),  altrimenti  si deve usare uno di quelli definiti Dr. Paolo Casoto, Ph.D - 2012
  70. 70. + Il costruttore  L’invocazione del costruttore di un TDA comporta l’inizializzazione con i valori di default di tutte le variabili di istanza del TDA  Nell’ordine di definizione delle variabili stesse  Prima dell’esecuzione del costruttore avviene l’inizializzazione delle variabili  Per facilitarne l’utilizzo all’interno di LINQ è stata introdotta una funzionalità interessante, l’inizializzazione dell’oggetto  Consente, in fase di allocazione di una nuova istanza di un oggetto, di passare al costruttore il valore di un insieme di proprietà, anche se non espressamente indicate nel costruttore  Lo vedremo nelle prossime lezioni quando parleremo di LINQ Dr. Paolo Casoto, Ph.D - 2012
  71. 71. + Esempi • Se la classe è: • Se invece è:public class Coordinate { public class Coordinate { private int x, y; private int x, y; public Coordinate(int a, int b) { } x = a; • si deve scrivere y = b;Coordinate p = } } new Coordinate(); • si deve scrivere Coordinate p = new Coordinate(2,3); Il costruttore “automatico” c’è solo se non c’è nessun altro costruttore Dr. Paolo Casoto, Ph.D - 2012
  72. 72. + Esempi 2 Se la classe è: public class Coordinate { private int x, y; public Coordinate(){ x = 0; y = 0; } public Coordinate(int a, int b){ x = a; y = b; } } Posso utilizzare entrambe le istruzioni Coordinate p = new Coordinate(); Coordinate p = new Coordinate(2,3); Dr. Paolo Casoto, Ph.D - 2012
  73. 73. + Esempio 3 Dr. Paolo Casoto, Ph.D - 2012
  74. 74. + Visibilità  Nei costruttori precedenti ho dovuto inventare nomi di parametri che fossero diversi da quelli delle variabili della classe  Cosa succede se usiamo gli stessi nomi? public class Coordinate { private int x, y; public Coordinate(int x, int y) { x = x; y = y; } } Dr. Paolo Casoto, Ph.D - 2012
  75. 75. + Il this  Regola di visibilità  Se nomi dei parametri = nomi degli attributi  Gli attributi vengono nascosti  (del costruttore, o di qualsiasi altro metodo)  Per accedervi occorre specificare che sono le variabili di “questo oggetto”, con la parola riservata this: Coordinate(int x, int y){ this.x=x; this.y=y;}  «assegno alla variabile x di questo oggetto il valore del parametro x, assegno alla variabile y di questo oggetto il valore del parametro y»  Coordinate(int x, int y) {x = x; y = y;}  «assegno al parametro x il valore del parametro x»... e quindi non modifico la variabile x della classe! Dr. Paolo Casoto, Ph.D - 2012
  76. 76. + Riassunto visibilità  Variabili locali a un blocco  for (int i = …)  Variabili locali a un metodo  static void m(int x){ int y...  Variabili locali a una classe  class C { int x...  public visibili anche all’esterno della classe  Private (o niente): solo all’interno della classe Dr. Paolo Casoto, Ph.D - 2012
  77. 77. + Il this  this può essere usato anche per riferirsi ad un altro costruttore (sovraccarico).public class Coordinate { questo private int x, y; costruttore public Coordinate(int x, int y) { this.x = x; this.y = y; } public Coordinate(int a):this(a,a){}} Dr. Paolo Casoto, Ph.D - 2012
  78. 78. + Costruttori e metodi sovraccarichi  A cosa servono?  Semplificano uso e allocazione delle variabili del TDA  Evitare duplicazione del codice  Con il this, o invocando altri metodi Coordinate c = new Coordinate(); Coordinate c = new Coordinate(0); Coordinate c = new Coordinate(0,0); Dr. Paolo Casoto, Ph.D - 2012
  79. 79. + Gli indici  Come per gli array sarebbe comodo disporre di una sintassi che ci consenta, mediante indici numerici o chiavi, di accedere alle strutture dati del nostro TDA  E.g.: come succede in Python e PHP  Ma come fare ?  In C# esiste un costrutto sintattico ad hoc, gli indici  Del tutto simili alle proprietà ma con accesso mediante indici Dr. Paolo Casoto, Ph.D - 2012
  80. 80. + Gli indici  Per realizzare un indice è sufficiente definire una proprietà con nome this, specificando fra parentesi quadre gli argomenti dell’indice. public class Frase { string[] parole= “Ecco la mia frase".Split(); public string this [int indiceParola] { get { return parole[indiceParola]; } set {parole[indiceParola] = value; } } } Dr. Paolo Casoto, Ph.D - 2012
  81. 81. + Il metodo ToString  Chi deve avere la conoscenza/responsabilità di sapere come visualizzare il valore di un TDA?  La classe! (cfr. Ora e UsaOra: scomodo!)  Si potrebbe definire un metodo nel TDA  static void Print(...)  ... ma si preferisce definire (vedremo perché)  static String ToString(...)  che restituisce una rappresentazione visualizzabile dell’istanza  (Vedremo l’invocazione automatica di ToString)  ToString verrà invocato nell’istruzione Console.Write*  In questo modo è possibile specificare come verranno visualizzati gli oggetti di una certa classe Dr. Paolo Casoto, Ph.D - 2012
  82. 82. + ToString  ToString restituisce la rappresentazione dell’oggetto in forma di stringa.public class Coordinate {private int x, y;...public static String ToString(Coordinate c){return “(” + c.x + “,” + c.y + “)”;}} class UsoCoordinate { Coordinate a = new ...; ... Console.WriteLine(Coordinate.toString(a)); } Dr. Paolo Casoto, Ph.D - 2012
  83. 83. + Ora.cspublic class Ora { private int ore, minuti, secondi; public Ora(int ore, int minuti, int secondi) { this.ore=ore; this.minuti=minuti; this.secondi=secondi; } public static void ImpostaOra(Ora x, int ore, int minuti, int secondi) { x.ore = ore; x.minuti = minuti; x.secondi = secondi; } public static int GetOre(Ora x) {return x.ore;} public static int GetMinuti(Ora x) {return x.minuti;} public static int GetSecondi(Ora x) {return x.secondi;} public static String ToString(Ora x) { return x.ore+":"+x.minuti+"."+x.secondi; }} Dr. Paolo Casoto, Ph.D - 2012
  84. 84. + UsaOra.csclass UsaOra { public static void Main(String[] args) { Ora x = new Ora(10,2,3); 10:2.3 Console.WriteLine(Ora.ToString(x)); Ora.ImpostaOra(x,12,2,0); Console.WriteLine(Ora.GetMinuti(x)); }} 2  (basterà scrivere Console.WriteLine(x); vedremo come) Dr. Paolo Casoto, Ph.D - 2012
  85. 85. + Pila (di interi limitata)  Pila (stack): struttura dati a gestione LIFO (Last In First Out, il primo che entra è l’ultimo che esce)  Operazioni:  push: aggiungi un elemento in cima  top: restituisce l’elemento in cima  pop: rimuove un elemento dalla cima  piena: dice se c’è ancora posto  vuota: dice se è vuota  Vediamo una versione semplice: la pila limitata di interi  C’è un numero massimo di elementi  Quindi potremo implementarla con un array Dr. Paolo Casoto, Ph.D - 2012
  86. 86. + Segnatura del TDA Pila Dr. Paolo Casoto, Ph.D - 2012
  87. 87. + Pila.cs (1/2)Stefano Mizzaro - TDA 2 Dr. Paolo Casoto, Ph.D - 2012
  88. 88. + Pila.cs (2/2) Dr. Paolo Casoto, Ph.D - 2012
  89. 89. + ProvaPila.cs/** Programma per la prova della classe Pila. */class ProvaPila { public static void Main (String[] args) { Pila p1 = new Pila(); p1 = Pila.push(p1,1); p1 = Pila.push(p1,2); p1 = Pila.push(p1,3); p1 = Pila.push(p1,4); Console.WriteLine(Pila.top(p1)); p1 = Pila.pop(p1); p1 = Pila.pop(p1); Console.WriteLine(Pila.top(p1)); p1 = Pila.push(p1,5); Console.WriteLine(Pila.top(p1)); }} Dr. Paolo Casoto, Ph.D - 2012
  90. 90. + public o non public…  Se non c’è il public gli attributi e metodi non sono visibili dal resto del programma al di fuori della classe  Per default se manca il public si applicano le seguenti regole:  Private per membri ed attributi di una classe  Diverso da Java, dove il default è una “specie di public”. Secondo voi per quale motivo ?  Vi ricordate le proprietà ?  Public per i membri di interfacce ed enumerazioni  Il private è importante Dr. Paolo Casoto, Ph.D - 2012
  91. 91. + Funzionale e procedurale  Nella versione precedente i metodi sono funzioni  Alcuni potrebbero essere procedure  push, pop  Lavorano per effetto collaterale (side effect) sui parametri  (Parametri che non sono tipi primitivi: viene passato il riferimento per valore => modifiche al parametro attuale si ripercuotono sul parametro formale)  Esercizio: rivedere la versione funzionale ed eliminare i side effect Dr. Paolo Casoto, Ph.D - 2012
  92. 92. + PilaP.cs (procedurale) public class PilaP { ... // ... come prima... /** push dellelemento e sulla pila p */ public static void push (PilaP p, int e) { if (!piena(p)) p.elementi[p.numElementi++] = e; } /** Elimina un elemento dalla cima della pila * p */ public static void pop(PilaP p) { if(!vuota(p)) p.numElementi--; } } Dr. Paolo Casoto, Ph.D - 2012
  93. 93. + ProvaPilaP.cs (procedurale)/** Programma per la prova della classe PilaP. */class ProvaPilaP { public static void Main (String[] args) { PilaP p1 = new PilaP(); PilaP.push(p1,1); PilaP.push(p1,2); PilaP.push(p1,3); PilaP.push(p1,4); Console.WriteLine(PilaP.top(p1)); PilaP.pop(p1); PilaP.pop(p1); Console.WriteLine(PilaP.top(p1)); PilaP.push(p1,5); Console.WriteLine(PilaP.top(p1)); }} Dr. Paolo Casoto, Ph.D - 2012
  94. 94. + Funzionale – procedurale (1/2)  Definizione metodo public static Pila Push (Pila p, int e) { if (!piena(p)) p.elementi[p.numElementi++] = e; return p; } public static void Push (PilaP p, int e) { if (!piena(p)) p.elementi[p.numElementi++] = e; } Dr. Paolo Casoto, Ph.D - 2012
  95. 95. + Funzionale – procedurale (2/2)class ProvaPila { public static void Main (String[] args) { Pila p1 = new Pila(); p1 = Pila.push(p1,1); ... p1 = Pila.push(Pila.push(p1,1),2); p1 = Pila.pop(p1); }}class ProvaPilaP { public static void main (String[] args) { PilaP p1 = new PilaP(); PilaP.push(p1,1); ... PilaP.pop(p1); }} Dr. Paolo Casoto, Ph.D - 2012
  96. 96. + Domande ??? Grazie a tutti per l’attenzione Dr. Paolo Casoto, Ph.D - 2012

×