Sezione 3.6
Tipi definiti dall'utente


Abbiamo appena visto un tipo di dato definito dall'utente (il programmatore): le strutture. Oltre a queste ci sono altri tipi definibili dall'utente. 

Definizione di propri tipi (typedef).

Il C++  permette di definire nuovi tipi basati su altri tipi di base o precedentemente definiti.  Per fare questo si usa la parola chiave typedef, nel seguente modo:   
typedef   tipo_esistente   nome_nuovo_tipo ;
in cui tipo_esistente è un tipo fondamentale del C++ o un altro tipo definito precedentemente e nome_nuovo_tipo è il nome assegnato al nuovo tipo che stiamo definendo. Ad esempio:        
typedef char C;
typedef unsigned int WORD;
typedef char field [50];
definiscono tre nuovi tipi: C, WORD e campo come char, unsigned int e char[50] rispettivamente. I nuovi tipi si possono usare in seguito scrivendo, ad esempio:               
C unchar, altrochar;
WORD parola;
field nome;
typedef si usa di solito per definire un tipo che viene usato molte volte nel programma e che è possibile debba essere cambiato in una nuova versione del programma. Si usa anche per dare un nome sintetico quando il tipo che si intende utilizzare ha un nome molto complesso.                             

Unioni

Le unioni permettono di utilizzare la stessa zona di memoria per memorizzare oggetti appartenenti a tipi differenti.  La sua dichiarazione è simile a quella delle strutture ma il suo significato è completamente diverso:                            
union nome_modello {
  tipo1 elemento1;
  tipo2 elemento2;
  tipo3 elemento3;
  .
  .
}
nome_oggetto;
Tutti gli elementi della union occupano lo stesso spazio di memoria. La dimensione di tale spazio è quella dell'elemento che ne richiede di più. Ad esempio:                                             
union tipi_t {
  char c;
  int i;
  float f;
  } x;
definisce tre elementi:                                                      
x.c
x.i
x.f
ciascuno di un tipo diverso. Essi non si possono usare contemporaneamente in quanto utilizzano la stessa memoria. In altre parole l'oggetto x può contenere un valore di tipo char o un valore di tipo int o un valore di tipo float ma soltanto uno di essi.  Questo spiega il nome union: l'insieme dei valori memorizzabili in x è l'unione dei tre insiemi di valori char , int e float .                                                          

Un possibile uso di una union è l'unione di un tipo elementare con una struttura o un array di elementi più piccoli. Ad esempio:

union mix_t{
  long l;
  struct {
    short hi;
    short lo;
    } s;
  char c[4];
} mix;
definisce tre modi di accedere allo stesso gruppo di 4 byte : mix.l, mix.s and mix.c.  Ecco i diversi modi di accedere:                                                                                          

Unioni anonime

In C++ possiamo avere delle unioni anonime. Se inseriamo una unione in una struttura senza indicare il nome di un oggetto (il nome che viene di norma posto alla fine, dopo la parentesi graffa }) l'unione si dice anonima e possiamo accedere direttamente agli elementi come fossero campi della struttura. Osserviamo la differenza tra le seguenti due dichiarazioni:
unione unione anonima
struct {
  char titolo[50];
  char autore[50];
  union {
    float euro;
    int lire;
  } prezzo;
} libro;
struct {
  char titolo[50];
  char autore[50];
  union {
    float euro;
    int lire;
  };
} libro;

La differenza è che nel primo caso abbiamo dato un nome (prezzo) all'unione mentre nel secondo caso lo abbiamo omesso.La differenza stà nel modo di accedere ai valori euro e lire. Nel primo caso si deve usare: 

libro.prezzo.euro
libro.prezzo.lire
mentre nel secondo basta scrivere:                                                                                                                                     
libro.euro
libro.lire
Ricordiamo che siccome si tratta di una unione i campi euro e lire occupano la stessa zona di memoria e quindi non si possono usare per memorizzare due valori diversi. In altre parole si può registrare il prezzo in euro oppure in lire ma non entrambi.                                                                                                                                                   

Enumerazioni (enum)

Le enumerazioni permettono di creare dei nuovi tipi che non sono basati sui tipi definiti precedentemente. La forma della dichiarazione è la seguente:  
enum nome_enum {
  id_valore1,
  id_valore2,
  id_valore3,
  .
  .
}
nome_oggetto;
Possiamo, ad esempio, creare un nuovo tipo color per memorizzare dei colori: 
enum colori {nero, blu, verde, viola, rosso, porpora, giallo, bianco};
Notiamo che nella dichiarazione non abbiamo usato nessun tipo di dato fondamentale.  Abbiamo creato un nuovo tipo di dato non basato su altri esistenti: il tipo colori, i cui possibili valori sono tutti e soli gli identificatori che abbiamo racchiuso tra parentesi graffe {}. Dopo aver dichiarato il tipo enumerazione colori possiamo scrivere: 
colori c;

c = blu;
if (c == verde) c = rosso;

In realtà il compilatore rappresenta gli elementi di un tipo enumerazione usando degli interi. Se non specificato altrimenti il primo elemento è rappresentato con 0 ed i successivi con 1,2,... in successione. Vi è una conversione implicita da tipo enum a int mentre in senso inverso occorre indicare esplicitamente la conversione di tipo. Ad esempio per calcolare il colore successivo possiamo scrivere

       c = colori(c+1);                                                                                                                                                                           


Precedente:
                                   3-5. Strutture

index
Successivo:
3-7. Vector e String.