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