Il C++ permette la definizione di nuovi tipi. I tipi definiti dal
programmatore vengono detti "Tipi definiti dall'utente" e possono essere
utilizzati ovunque e` richiesto un identificatore di tipo (con rispetto alle regole
di visibilita` viste precedentemente). I nuovi
tipi vengono definiti applicando dei costruttori di tipi ai tipi primitivi
(quelli forniti dal linguaggio) o a tipi precedentemente definiti dall'utente.
I costruttori di tipo disponibili sono:
int Array[10];introduce con il nome Array 10 variabili di tipo int; il tipo di Array e` array di 10 int(eri).
< NomeTipo > < Identificatore >[ < NumeroElementi > ];Al solito Tipo puo` essere sia un tipo primitivo che uno definito dal programmatore, Identificatore e` un nome scelto dal programmatore per identificare l'array, mentre NumeroElementi deve essere un intero positivo.
float Pippo[10]; float Pluto; Pippo[0] = 13.5; // Assegna 13.5 al primo elemento Pluto = Pippo[9]; // Seleziona l'ultimo elemento di Pippo // e lo assegna a PlutoE` anche possibile dichiarare array multidimensionali (detti array di array o piu` in generale matrici) specificando piu` indici:
long double Qui[3][4]; // una matrice 3 x 4 short Quo[2][10]; // 2 array di 10 short int int SuperPippo[12][16][20]; // matrice 12 x 16 x 20E` anche possibile specificare i valori iniziali dei singoli elementi dell'array tramite una inizializzazione aggregata:
int Pippo[5] = { 10, -5, 6, 110, -96 }; short Pluto[2][4] = { 4, 7, 1, 4, 0, 3, 5, 9 ); float Minni[ ] = { 1.1, 3.5, 10.5 }; long Manetta[ ][3] = { 5, -7, 2, 1, 0, 5 };La prima dichiarazione e` piuttosto semplice, dichiara un array di 5 elementi e per ciascuno di essi indica il valore iniziale a partire dall'elemento 0. La seconda dichiarazione e` identica alla prima se si tiene conto che il primo indice a variare e` l'ultimo, cosi` che gli elementi vengono inizializzati nell'ordine Pluto[0][0], Pluto[0][1], ..., Pluto[1][3].
char Topolino[ ] = "investigatore" ;La dimensione dell'array e` pari a quella della stringa "investigatore" + 1, l'elemento in piu` e` dovuto al fatto che in C++ le stringhe per default sono tutte terminate dal carattere nullo ('\0') che il compilatore aggiunge automaticamente.
char Topolino[ ] = "investigatore" ; Topolino[4] = 't'; // assegna 't' al quinto elemento Topolino[ ] = "basso"; // errore Topolino = "basso"; // ancora erroreE` possibile inizializzare un array di caratteri anche nei seguenti modi:
char Topolino[ ] = { 'T', 'o', 'p', 'o', 'l', 'i', 'n', 'o'}; char Pluto[5] = { 'P', 'l', 'u', 't', 'o' };In questi casi pero` non si ottiene una stringa terminata da '\0', ma semplici array di caratteri il cui numero di elementi e` esattamente quello specificato.
struct Persona { char Nome[20]; unsigned short Eta; char CodiceFiscale[16]; };La precedente dichiarazione introduce un tipo struttura di nome Persona composto da tre campi: Nome, un array di 20 caratteri; Eta, un intero positivo; CodiceFiscale, un array di 16 caratteri.
struct < NomeTipo > { < Tipo > < NomeCampo > ; /* ... */ < Tipo > < NomeCampo > ; };Si osservi che la parentesi graffa finale deve essere seguita da un punto e virgola, questo vale anche per le unioni, le enumerazioni e per le classi.
struct Persona { char Nome[20]; unsigned short Eta; char CodiceFiscale[16]; }; Persona Pippo = { "Pippo", 40, "PPP718F444E18DR0" }; Persona AmiciDiPippo[2] = { "Pluto", 40, "PLT", "Minnie", 35, "MNN" }; // esempi di uso di strutture: Pippo.Eta = 41; unsigned short Var = Pippo.Eta; strcpy(AmiciDiPippo[0].Nome, "Topolino");Innanzi tutto viene dichiarato il tipo Persona e quindi si dichiara la variabile Pippo di tale tipo; in particolare viene mostrato come inizializzare la variabile con una inizializzazione aggregata del tutto simile a quanto si fa per gli array, eccetto che i valori forniti devono essere compatibili con il tipo dei campi e dati nell'ordine di dichiarazione dei campi. Viene mostrata anche la dichiarazione di un array i cui elementi sono di tipo struttura, e il modo in cui eseguire una inizializzazione fornendo i valori necessari all'inizializzazione dei singoli campi di ciascun elemento dell'array (nell'ordine coerente alle dichiarazioni). Le righe successivi mostrano come accedere ai campi di una variabile di tipo struttura, in particolare l'ultima riga assegna un nuovo valore al campo Nome del primo elemento dell'array tramite una funzione di libreria. Si noti che prima viene selezionato l'elemento dell'array e poi il campo Nome di tale elemento; analogamente se e` la struttura a contenere un campo di tipo non primitivo, prima si seleziona il campo e poi si seleziona l'elemento del campo che ci interessa:
struct Data { unsigned short Giorno, Mese; unsigned Anno; }; struct Persona { char Nome[20]; Data DataNascita; }; Persona Pippo = { "pippo", 10, 9, 1950 }; Pippo.Nome[0] = 'P'; Pippo.DataNascita.Giorno = 15; unsigned short UnGiorno = Pippo.DataNascita.Giorno;Per le strutture, a differenza degli array, e` definito l'operatore di assegnamento:
struct Data { unsigned short Giorno, Mese; unsigned Anno; }; Data Oggi = { 10, 11, 1996 }; Data UnaData = { 1, 1, 1995}; UnaData = Oggi;Cio` e` possibile per le strutture solo perche`, come vedremo, il compilatore le tratta come classi i cui membri sono tutti pubblici.
// con riferimento al tipo Data visto sopra: struct DT { unsigned short Giorno, Mese; unsigned Anno; }; Data Oggi = { 10, 11, 1996 }; DT Ieri; Ieri = Oggi; // Errore di tipo!
union TipoUnione { unsigned Intero; char Lettera; char Stringa[500]; };Come per i tipi struttura, la selezione di un dato campo di una variabile di tipo unione viene eseguita tramite l'operatore di selezione . (punto).
enum < NomeTipo > { < Identificatore >, /* ... */ < Identificatore > };Esempio:
enum Elemento { Idrogeno, Elio, Carbonio, Ossigeno }; Elemento Atomo = Idrogeno;Gli identificatori Idrogeno, Elio, Carbonio e Ossigeno costituiscono l'intervallo dei valori del tipo Elemento. Si osservi che come da sintassi, i valori di una enumerazione devono essere espressi tramite identificatori, non sono ammessi valori espressi in altri modi (interi, numeri in virgola mobile, costanti carattere...), inoltre gli identificatori utilizzati per esprimere tali valori devono essere distinti da qualsiasi altro identificatore visibile nello scope dell'enumerazione onde evitare ambiguita`.
enum Elemento { Idrogeno, Elio, Carbonio, Ossigeno }; Elemento Atomo = Idrogeno; int Numero; Numero = Carbonio; // Ok! Atomo = 3; // Errore!Nell'ultima riga dell'esempio si verifica un errore perche` non esiste un operatore di conversione da int a Elemento, mentre essendo i valori enumerazione in pratica delle costanti intere, il compilatore e` in grado di eseguire la conversione a int. E` possibile forzare il valore intero da associare ai valori di una enumerazione:
enum Elemento { Idrogeno = 2, Elio, Carbonio = Idrogeno - 10, Ferro = Elio + 7, Ossigeno = 2 };Non e` necessario specificare un valore per ogni identificatore dell'enumerazione, non ci sono limitazioni di segno e non e` necessario usare valori distinti. Si puo` utilizzare un identificatore dell'enumerazione precedentemente definito e non e` bisogna specificare un valore intero per ciascun identificatore dell'enumerazione.
typedef < Tipo > < Alias > ;Il listato seguente mostra alcune possibili applicazioni:
typedef unsigned short int PiccoloIntero; typedef long double ArrayDiReali[20]; typedef struct { long double ParteReale; long double ParteImmaginaria; } Complesso;Il primo esempio mostra un caso molto semplice: creare un alias per un nome di tipo. Nel secondo caso invece viene mostrato come dichiarare un alias per un array di 20 long double. Infine il terzo esempio e` il piu` interessante perche` mostra un modo alternativo di dichiarare un nuovo tipo; in realta` ad essere pignoli non viene introdotto un nuovo tipo: la definizione di tipo che precede l'identificatore Complesso dichiara una struttura anonima e poi l'uso di typedef crea un alias per quel tipo struttura. E` possibile dichiarare tipi anonimi solo per i costrutti struct, union e enum e sono utilizzabili quasi esclusivamente nelle dichiarazioni (come nel caso di typedef oppure nelle dichiarazioni di variabili e costanti). La keyword typedef e` utile per creare abbreviazioni per espressioni di tipo complesse, soprattutto quando l'espressione di tipo coinvolge puntatori e funzioni.