C#

LE CLASSI - 1

Non perderò tempo ad illustrare l'importanza del concetto di "classe" nella programmazione attuale. Potrete trovare materiale a perdita d'occhio su questo argomento su libri e ovviamente anche su Internet. C# è un linguaggio a oggetti e gli oggetti vengono espressi tramite le classi, appunto, introdotte dalla keyword class. Ricordiamoci che abbiamo già incontrato questa parola in tutti i programmi fin qui realizzati, anche il nostro entry point, il metodo Main, deve essere inglobato in una classe.
Le classi vivono nello heap
invece che nello stack come avviene invece per i tipi valore, anche se un coinvolgimento, minuscolo, dello stack permane. In modo molto sommario si potrebbe infatti immaginare questa situazione come segue:



Formalmente, stando ad un aspetto minimale, la denizione di una classe avviene così:

class nomeclasse
{
}

Una classe fatta così non serve ovviamente a nulla. In realtà il corredo di una classe può contenere membri dati e membri funzione. I primi a loro volta posso essere campi, costanti ed eventi. Per iniziare introduciamo i campi, in parole molto povere delle variabili che sono contenute all'interno della classe.

  Esempio 20.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;

class Persona
{
  int anni;
  string nome;
}

class Test
{
  public static void Main()
  {
    Persona p1 = new Persona();
  }
}

In questo semplice esempio dalla riga 3 alla 7 viene definita una classe chiamata Persona nella quale sono presenti due campi: anni, di tipo intero e nome di tipo string. Alla riga 13 questa classe viene istanziata in pratica viene creata una variabile avente come tipo la classe da cui deriva assumendone tutte le caratteristiche. In questo meccanismo sta uno dei grandi punti di forza delle classi, ovvero di contenere caratteristiche decise autonomamente dal programmatore.
Di default i campi sono definiti privati e quindi non accessibili all'esterno. Ampliamo quindi l'esempio precedente come segue:

  Esempio 20.2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;

class Persona
{
  public int anni;
  public string nome;
}

class Test
{
  public static void Main()
  {
    Persona p1 = new Persona();
    p1.nome = "Pippo";
    p1.anni = 30;
  }
}

alle righe 14 e 15 vengono inzializzati i campi nome e anni relativi all'istanza p1. L'accesso a tali campi avviene, come già noto, con l'operatore . (punto). Va specificato, qualora non fosse ancora chiaro, che ogni istanza ha un suo identificatore e, come ogni variabile, vive di vita propria. Un'altra istanza avrebbe propri campi ad essa solo appartenenti, insomma. 
Abbiamo usato il modificatore public ma sono ovviamente utilizzabili tutti quelli disponibili sui campi:

private - protected - internal - public - static - new - unsafe - readonly - volatile.

I campi che abbiamo generato negli esempi 20.1 e 20.2 sono privi di qualsiasi inizializzazione; questa, come si capisce, è opzionale e quindi, volendo, avremmo ad esempio potuto scrivere:

public int anni = 10;

alla riga 5. I campi non inizializzati hanno il valore di default previsto per il loro tipo.
In fase di dichiarazione di campi che debbano condividere lo gli stessi modificatori è possibile ricorrere ad una sorta di inizializzazione multipla:

static int x = 7;
           y = 8;

Altra caratteristica della classi sono i metodi. Li abbiamo già incontrati, si tratta di sequenze di una o più istruzioni di qualsiasi natura che possono essere richiamate in blocco. Nell'ambito della classi non cambia nulla.

  Esempio 20.3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;

class Persona
{
  public int anni;
  public string nome;
  public void presenta()
  {
    Console.WriteLine(this.nome);
  }
}

class Test
{
  public static void Main()
  {
    Persona p1 = new Persona();
    p1.nome = "Pippo";
    p1.anni = 30;
    p1.presenta();
  }
}

Nell'esempio 20.3 la classe Persona presenta dalla riga 7 alla 10 la definizione di un metodo di nome "presenta" che stampa a video il contenuto del campo "nome". Tale metodo viene richiamato alla riga 20. All'interno è interessante notare la keyword this, il cui scopo, come forse intuirete, è quello di far riferimento all'istanza corrente della classe. In questo modo è permesso accedere ai campi definiti nella classe stessa. Essa è anche utile per risolvere eventuali ambiguità, che sarebbero da evitarsi, qualora un parametro in ingresso avesse lo stesso nome di un campo all'interno della classe. Ad esempio:

  Esempio 20.4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;

class Num
{
  public int xx;
  public Num(int xx)
  {
    this.xx = xx;
  }
}

class Test
{
  public static void Main()
  {
    Num n1 = new Num(5);
    Console.WriteLine(n1.xx);
  }
}
 
provate a vedere cosa succede se eliminate la parolina this... già il compilatore, pur permettendo la cosa, esprimerà i suoi dubbi. Ad ogni modo, l'Intellisense di Visual Studio, se lo usate, vi può aiutare in situazioni simili.

Tornando al discorso dei membri interni alla classe, un discorso interessante lo merita il modificatore static. esso è utile in situazioni nelle quali si voglia risparmiare memoria evitando di allocare elementi inutili. Per esempio supponiamo che un campo in una classe debba conservare sempre lo stesso valore:

  Esempio 20.5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;

class Classe
{
  public int xx;
  static int yy = 0;
  public Classe (int x)
  {
    xx = x;
  }
}

class Test
{
  public static void Main()
  {
    Classe C1 = new Classe(2);
    Classe C2 = new Classe(3);
    Classe C3 = new Classe(4);
  }
}

In questo caso abbiamo creato 3 istanze di classe. Per ciascuna di esse il campo xx verrà allocato col suo valore mentre yy lo troveremo una sola volta in memoria e sarà "puntato" da tutte le istanze create. Come detto, questo porta un risparmio in termini di memoria. Per inciso, alla riga 7 abbiamo anticipato il discorso relativo ai costruttori, che trovate nel paragrafo successivo.

Ovviamente, vi possono anche essere i metodi statici all'interno della classe... il nostro sempre presente entry point "static void Main" che cos'è? Quello. Si tratta di un metodo che può essere utilizzato anche senza creare un'istanza della classe. Semplicemente, basta richiamare il nome della classe stessa, come già visto in altri esempi. Per ribadire:

class Classe
{
  public static void Saluta()
  {
    Console.WriteLine("Ciao");
  }
}

class Test
{
  public static void Main()
  {
    Classe.Saluta();
  }
}

Credo che non valga nemmeno la pena di sspiegare ulteriormente il codice qui sopra.

L'approccio visto in questi esempi è puramente introduttivo. Una pessima impostazione è quella di porre tutti i membri come pubblici il che, si capisce, rende la classe vulnerabile, questo non è importante in programmi banali come quelli presentati ma in progetti più ampi e condivisi proprio non va.
Fate qualche prova, nel prossimo paragrafo si inizierà a fare sul serio.