Il concetto di classe è centrale in C#, così come in ogni altro linguaggio di programmazione orientato agli oggetti. In questa lezione cercheremo di introdurre il lettore ai concetti basilari circa il funzionamento delle classi. Per prima cosa, tuttavia, dobbiamo definire con precisione cos’è una classe.
Cos’è una classe? Cos’è un oggetto?
Una classe è un modo di rappresentare una serie di oggetti. Pensiamo alle biciclette: hanno due ruote, hanno un colore, hanno una dimensione delle ruote, quindi tutte hanno delle caratteristiche in comune. A livello di programmazione la bicicletta genericamente intesa è la classe, mentre la mia bicicletta è un oggetto che appartiene alla classe "bici".
Come avrete capito le classi sono essenzialmente dei modelli in base a cui creare oggetti.
Un semplice esempio di classe in C#
Osserviamo l’esempio seguente per meglio comprendere quanto detto:
using System;
class Esempio
{
public static void Main()
{
bici MiaBici=new bici();
MiaBici.colore="Verde";
MiaBici.FaiUnaPedalata();
int velocita = MiaBici.DammiVelocita(3);
}
}
public class bici
{
public string modello;
public string colore;
public void FaiUnaPedalata()
{
System.Console.WriteLine("Faccio una pedalata.");
}
public int DammiVelocita(int marcia)
{
return marcia*10;
}
}
In questo codice di esempio abbiamo un metodo Main (che deve esserci sempre perché altrimenti il compilatore non sa da dove partire) ed una classe "bici" che ha delle proprietà che sono il "modello" e il "colore". All’interno della nostra classe vengono, inoltre, definiti due metodi:
- il metodo "FaiUnaPedalata" è un metodo senza valore di ritorno e si limita a stampare un messaggio a video;
- il metodo "DammiVelocita" è un metodo con valore di ritorno di tipo int: sulla base di un parametro in ingresso (la marcia della mia bicicletta), restituirà la velocità.
Nel Main viene istanziato un oggetto di tipo bici e a tale oggetto diamo il nome "MiaBici". Si imposta poi il colore e si esegue prima il metodo "FaiUnaPedalata" e poi si crea una variabile "velocita" cui si assegna il valore restituito dal metodo "DammiVelocita" cui abbiamo passato il valore 3 come parametro.
Osservate che all’interno della classe "bici" viene sempre utilizzato il livello di accessibilità public e questo fa sì che le proprietà e le funzioni siano accessibili anche dall’esterno della classe, nel nostro esempio dal Main (se avessimo usato il ivello di accessibilità private non sarebbe stato possibile accedervi dal Main).
Classi: un po’ di teoria
Ogni classe contiene attributi (cioè i dati) e metodi (cioè le funzioni con cui manipolare i dati). La classe definisce quali dati e comportamenti ogni particolare oggetto (definito istanza) può gestire.
I dati e le funzioni presenti allinterno di una classe sono definiti membri di tale classe.
Microsoft distingue tra membri dati e membri funzioni. I primi sono membri che contengono dati, come campi e costanti; i secondi sono membri che forniscono funzionalità per manipolare i dati della classe, come metodi, proprietà, costruttori, operatori, indicizzatori.
Oltre ai membri le classi possono contenere anche altre classi annidate.
Metodi
In C# la definizione di un metodo consiste di un modificatore che ne indichi il tipo di accessibilità, seguito dal tipo dati restituito, dal nome del metodo e da una lista (opzionale) di argomenti di input (o parametri) racchiusa tra parentesi tonde. Vediamo, di seguito, la sintassi per la definizione di un metodo:
[accessibilità] tipo_restituito NomeMetodo([parametri])
{
//Corpo del metodo
}
Ogni parametro è costituito da un tipo di dato e da un nome attraverso cui può essere utilizzato nel corpo del metodo.
In generale i parametri possono essere passati ai metodi in due modi: riferimento o valore:
- quando una variabile viene passata come riferimento, il metodo ottiene un puntatore a tale variabile e tutte le modifiche fatte vengono trasmesse alla variabile originale anche dopo luscita dal metodo;
- quando invece una variabile viene passata tramite valore il metodo crea una copia di tale variabile e ogni modifica effettuata viene persa dopo luscita dal metodo.
Ad esempio una variabile di tipo int viene gestita come valore, mentre una variabile array viene gestita come riferimento e questo in C# viene gestito automaticamente, non bisogna specificare nulla allinterno del codice. Un caso a parte poi è costituito dalle stringhe. Le stringhe infatti sono immutabili, per alterare un valore stringa bisogna creare una nuova stringa. Quindi le stringhe non seguono il tipico comportamento degli altri tipi di dati.
Metodi e valori di ritorno
I metodi possono avere o non avere un valore di ritorno. Se non hanno un valore di ritorno il tipo_restituito sarà void.
Overload dei metodi
Il linguaggio C# supporta anche il cosiddetto overload dei metodi. Esso consiste nella possibilità di avere più versioni di uno stesso metodo con firme differenti. Questo significa stesso nome ma un differente numero e/o tipo di parametri come nel seguente esempio:
void MetodoTest (string risultato)
{
// implementazione
}
void MetodoTest (int risultato)
{
// implementazione
}
void MetodoTest (intvalore, string risultato)
{
// implementazione
}
Le proprietà
Altri elementi fondamentali di una classe sono le proprietà. Una proprietà consiste in un metodo (o coppia di metodi) da utilizzare come un campo.
Per definire una proprietà la sintassi è la seguente:
public string NomeProprietà {
get {
// restituisce il valore della proprietà
}
set {
// imposta valore proprietà
}
}
Il metodo get non ha parametri e deve restituire un valore dello stesso tipo della proprietà. Non è necessario nemmeno specificare un parametro per il metodo set, in questo caso il compilatore assume che esso ne richieda uno denominato value come nel seguente esempio:
private int peso;
public int Peso {
get {
return peso;
}
set {
peso = value;
}
}
Ovviamente è possibile creare metodi di sola lettura o sola scrittura omettendo rispettivamente il set e il get.
Il costruttore
All’interno di una classe esiste un metodo particolare che prende il nome di costruttore. E’ bene precisare che non è obbligatorio inserire un costruttore nelle classi perché, se non è presente, il compilatore ne genera automaticamente uno per ogni classe.
La sintassi per dichiarare un costruttore corrisponde a quella di un metodo che ha lo stesso nome della classe e non ha un tipo di ritorno.
Vediamo, di seguito, un esempio di classe dotata di un costruttore.
public class bici
{
public string modello;
public string colore;
public bici()
{
this.colore="Nero";
}
}
Nel codice qui sopra potete vedere che esiste una funzione di nome "bici", proprio come la stessa classe. Questo è il costruttore e serve, per esempio, quando vogliamo assegnare di default certi valori alle istanze. Infatti all’interno di esso ho usato:
this.colore="Nero"
che appunto assegna il valore di default Nero a tutte le bici che verranno create con la classe a meno che lo sviluppatore non indichi un colore differente. Osservate l’uso di this: questa parola non è altro che la variabile che punta all’istanza corrente.