02.06.2013 Views

PROGRAMMAZIONE A OGGETTI (OOP) Lezione 4 prj Mesa (Prof ...

PROGRAMMAZIONE A OGGETTI (OOP) Lezione 4 prj Mesa (Prof ...

PROGRAMMAZIONE A OGGETTI (OOP) Lezione 4 prj Mesa (Prof ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>PROGRAMMAZIONE</strong> A <strong>OGGETTI</strong> (<strong>OOP</strong>) <strong>Lezione</strong> 4 <strong>prj</strong> <strong>Mesa</strong> (<strong>Prof</strong>. Ing N. Muto)<br />

In questa lezione applicheremo tutti i concetti teorici fin qui esposti, sarà presentato codice<br />

sviluppato in C# sviluppato con l'IDE (Integrated Development Environnemt) di Visual Studio<br />

Express Edition 2008, liberamente scaricabile ed installabile.


Programmazione a oggetti in C#<br />

Dopo aver affrontato i concetti di base e le caratteristiche portanti della <strong>OOP</strong> è ora arrivato il<br />

momento di imparare concretamente come programmare ad oggetti con un linguaggio reale ed<br />

in particolare il C#. Questo linguaggio è la “dote” che ha portato in casa Microsoft Anders<br />

Hejlsberg l'inventore di “Delphi”, un linguaggio in Object Pascal che ha avuto un enorme suc-<br />

cesso.<br />

La sintassi del C# prende spunto sia da quella di Delphi che di C++, di Java e di Visual<br />

Basic per gli strumenti di programmazione visuale e per la sua semplicità. Il risultato è un lin-<br />

guaggio con meno simbolismo rispetto a C++, meno elementi decorativi rispetto a Java, ma co-<br />

munque orientato agli oggetti in modo nativo.<br />

Rispetto al C ed al C++, C# risulta più semplice e sicuro, in particolare possiamo elencare<br />

le seguenti differenze:<br />

• I puntatori possono essere utilizzati solo in particolari blocchi di codice marcati come<br />

"unsafe".<br />

• In molte operazioni aritmetiche vengono controllati eventuali "overflow".<br />

• Gli oggetti dinamici non vengono deallocati esplicitamente; la loro rimozione viene<br />

gestita automaticamente (implicitamente) dal "garbage-collector" quando non esistono<br />

più riferimenti a tali oggetti. Questa gestione evita i due problemi ben noti dei dangling<br />

pointer e del memory leak, anche se con un'ovvia riduzione delle prestazioni.<br />

• Come in Java, è possibile ereditare da una sola classe (diversamente da quanto avviene<br />

in C++) ma è possibile implementare un numero indefinito di interfacce.<br />

• Le sole conversioni implicite consentite sono quelle "safe", ovvero che non espongono al<br />

rischio di perdita di dati causata dalla diversa tipologia di dato. Ad esempio non sono<br />

consentite conversioni implicite fra integer e boolean o fra enumerati ed integer.<br />

• C# non possiede i "template" (tipici del C++) ma nella versione 2.0 sono stati introdotti i<br />

"generic".<br />

Rispetto a Java invece possiamo elencare questi punti:<br />

Java utilizza i commenti Javadoc-sintax per generare la documentazione dal codice sorgen-<br />

te, mentre C# utilizza la sintassi XML nei commenti per lo stesso scopo.<br />

• Quello che in Java è chiamato package, in C# viene chiamato namespace o "spazio di<br />

nomi". Un ulteriore livello di organizzazione in C# è costituito dagli "assembly", che<br />

possono contenere al proprio interno diversi spazi di nomi.


Dopo queste indicazioni tecniche specifiche per il cui approfondimento rimandiamo ai link<br />

presenti in Internet, veniamo finalmente ad usare il C# per creare una classe.<br />

se:<br />

Per prima cosa vediamo la “sintassi” ossia come si scrive o meglio “implementa” una clas-<br />

public class retta {<br />

}<br />

//qui vanno aggiunte le proprietà e i metodi...<br />

La classe precedente è quindi una classe “vuota”, serve solo a far vedere la forma; ora ve-<br />

diamo invece un esempio di classe completa:<br />

//questa classe rappresenta l'entità “retta” espressa nella forma implicita ax + by +c = 0;<br />

class retta {<br />

}<br />

// questa parte contiene la dichiarazione delle proprietà o attributi<br />

public double a;<br />

public double b;<br />

public double c;<br />

private double m; //questo attributo è dichiarato private (privato) per nasconderlo al resto del codice<br />

//qui di seguito è presente il costruttore della classe<br />

public retta(double pa, double pb, double pc )<br />

{<br />

a= pa;<br />

b= pb;<br />

c= pc;<br />

}<br />

//questo metodo consente di calcolare il coefficiente angolare noti i coefficienti della retta in forma implicita<br />

public double CalcolaM(){<br />

if(a!=0) {<br />

m=-b/a;<br />

return m;<br />

}<br />

else {<br />

Console.WriteLine("Impossibile eseguire il calcolo");<br />

return 0;<br />

}<br />

}<br />

Precisiamo alcune cose che abbiamo visto nel codice sopra riportato: la parola chiave<br />

“private” detto anche modificatore di visibilità, rende gli attributi ed i metodi a cui è applicata<br />

visibili e quindi utilizzabili SOLO dai metodi della classe stessa. Se non si specifica alcun<br />

modificatore, si presuppone che valga “private”.


Il metodo “public retta(double pa, double pb, double pc ) ” è SPECIALE e si chiama<br />

COSTRUTTORE della classe. Come si può notare ha lo stesso nome della classe, non<br />

restituisce alcun valore ed è di tipo “public”. Il suo scopo è quello di “istanziare” la classe, ossia<br />

creare l'oggetto reale a partire dalla “ricetta” definita nella classe. Proprio perché è un codice<br />

che viene eseguito nel momento iniziale della “vita” di un oggetto, è adatto anche a contenere<br />

delle istruzioni (azioni) che vanno compiute subito dopo la creazione dell'oggetto stesso, come<br />

ad esempio caricare in alcune variabili dei valori iniziali. Infatti, se riguardiamo le istruzioni in<br />

cui si creano gli attributi, notiamo che non viene specificato alcun valore iniziale.<br />

Vediamo ora come si effettua l'istanza della classe, ossia si crea un oggetto realmente<br />

esistente nella memoria centrale del calcolatore, a partire dalla sua ricetta, ossia dalla classe:<br />

namespace RisolutoreSis1G<br />

{<br />

class Program<br />

{<br />

static void Main(string[] args)<br />

{<br />

Double A=0;<br />

Double B=0;<br />

Double C=0;<br />

Double XSoluzione = 0;<br />

Double YSoluzione = 0;<br />

Console.WriteLine("* PROGRAMMA PER LA RISOLUZIONE DI SISTEMI DI DUE RETTE *");<br />

Console.WriteLine("Inserisci a, b, c per la prima retta");<br />

A=Convert.ToDouble(Console.ReadLine());<br />

B=Convert.ToDouble(Console.ReadLine());<br />

C=Convert.ToDouble(Console.ReadLine());<br />

retta r1 = new retta(A,B,C); //questa istruzione crea l'oggetto r1 a partire dalla classe “retta”<br />

Console.WriteLine("Inserisci a, b, c per la seconda retta");<br />

A = Convert.ToDouble(Console.ReadLine());<br />

B = Convert.ToDouble(Console.ReadLine());<br />

C = Convert.ToDouble(Console.ReadLine());<br />

retta r2 = new retta(A, B, C); //questa istruzione crea l'oggetto r2 sempre a partire dalla classe “retta”<br />

//controllo che le rette non siano coincidenti<br />

if((r1.a/r2.a==r1.b/r2.b)&&(r1.b/r2.b==r1.c/r2.c)) {<br />

Console.WriteLine("Rette coincidenti: Infinite soluzion1!");<br />

}<br />

//controllo che le rette non siano parallele<br />

else if (r1.CalcolaM() == r2.CalcolaM()) //questa istruzione usa il metodo CalcolaM<br />

{<br />

Console.WriteLine("Rette parallele: Nessuna soluzione!");<br />

}<br />

else {<br />

//Eseguo il calcolo per trovare l'intersezione


}<br />

}<br />

YSoluzione = (((r2.a*r1.c)/r1.a)-r2.c)/(-r2.a*r1.b+r2.b);<br />

XSoluzione = -r1.c / r1.a - r1.b / r1.a * YSoluzione;<br />

Console.WriteLine("Le soluzioni sono X= {0} Y={1}", XSoluzione, YSoluzione);<br />

}<br />

Console.ReadLine();<br />

Commentiamo le parti evidenziate in giallo che sono relative alla creazione dell'oggetto:<br />

retta r1 = new retta(A,B,C);<br />

r1: è il nome della variabile composta che stiamo per creare; si tratta dell'OGGETTO.<br />

retta: è il nome della classe che stiamo usando per creare l'oggetto r1<br />

new: è un operatore che, partendo dalla ricetta “retta” è in grado di creare l'oggetto r1.<br />

Notare che new ha SEMPRE bisogno del costruttore e se avessimo creato una classe<br />

senza un costruttore dichiarato esplicitamente, new avrebbe comunque usato un costruttore<br />

creato implicitamente dal compilatore.<br />

Una volta creato l'oggetto ci rimane da capire come si usa e per questo basta esaminare la<br />

riga di codice evidenziata in verde e qui riportata:<br />

else if (r1.CalcolaM() == r2.CalcolaM())<br />

Ciò che notiamo è l'utilizzo del “.” ossia del carattere punto: r1.CalcolaM() è come dire, usa<br />

l'oggetto r1 ed in particolare “accedi” al metodo CalcolaM()<br />

Analogamente possiamo accedere al metodo CalcolaM() dell'altro oggetto retta r2.<br />

Ovviamente questo è possibile perché il metodo CalcolaM() è dichiarato “public”!<br />

Cosa accadrebbe infatti se provassimo a scrivere:<br />

... if( r1.m == r2.m )...<br />

Accadrebbe che il compilatore ci avviserebbe che m non è accessibile!<br />

Come applicazione concreta di quanto fin qui spiegato si lasciano i seguenti esercizi da svilup-<br />

pare con l'ambiente di sviluppo gratuito Visual Studio Express Edition 2008 o successivi, che<br />

sono gratuiti e completi.<br />

Esercizio 1:<br />

Definire una classe per gestire un cellulare. Disegnare anche il modello UML. La classe deve comprendere<br />

almeno tre attributi di cui uno almeno private e contenere due metodi oltre al costruttore.<br />

Esercizio 2:<br />

Definire una classe per gestire il numero complesso nella forma: Z = a+jb. Disegnare anche il modello<br />

UML. La classe deve contenere due metodi in grado di calcolare e restituire il modulo e l'argomento del<br />

numero complesso.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!