next up previous contents index
Next: Argomenti con valori default Up: Approfondimenti. I files d'intestazione Previous: Approfondimenti. I files d'intestazione   Indice   Indice analitico

Typedef

In C come in C++, è possibile creare dei sinonimi di tipo tramite typedef, che sta infatti per TYPE DEFinition (= ``definizione di tipo''); la sintassi è la seguente:
typedef tipo_esistente identificatore_nuovo_tipo
Si faccia bene attenzione che typedef non è un derivatore di tipo bensì esso crea semplicemente dei sinonimi sintattici, come possono esserlo tra di loro i++ e i+=1. Vediamo il seguente semplice esempio:

// ex8_1_1
#include <iostream.h>

typedef int* puntatore_a_interi;

void funzione (puntatore_a_interi a) {
  (*a)++;
}

void main() {
  puntatore_a_interi a = new int(7);
  cout << *a << "\n";
  funzione (a);
  cout << *a << "\n";
}

output:
7
8

Certo definire un tipo puntatore_a_interi probabilmente non è una buona idea: il tipo int* è ben noto a qualunque programmatore per cui introdurre un suo sinonimo creerebbe confusione. Un esempio sensato potrebbe invece essere il seguente:


// ex8_1_2
#include "listasemplice.h"

typedef elem* Lista;

void main() {
  Lista lista;  // equivale a `elem* lista'
  inizializza (lista);
  for (int i = 0; i < 5; i++)
    insTesta (lista, i);
  stampa (lista, 5);
}

output:
 4 3 2 1 0

Siccome una lista prende il nome dal suo primo elemento, dobbiamo identificarla tramite un elem*; tuttavia non è affatto intuitivo definire


elem* lista;
quindi in questo caso introdurre il sinonimo sintattio Lista aumenta la chiarezza del codice; infatti la definizione di una lista è in questo modo

Lista lista;
Noi sappiamo bene che il tipo Lista in realtà non esiste, ma è solo un sinonimo di elem*, ma per un utilizzatore del nostro codice tale sottigliezza non è rilevante: egli vede semplicemente un tipo Lista e ne fa uso appropriato.

C'è un altro uso tipico di typedef. Quando scriviamo delle funzioni che lavorano su di una certa struttura dati (lista, array) spesso non ha importanza il tipo di dato contenuto nella struttura stessa; tuttavia siamo forzati ad utilizzare un tipo perché il C++ sappiamo essere molto rigido riguardo alla dichiarazione dei tipi utilizzati8.1. Ad esempio, se abbiamo una funzione che inverte l'ordine degli elementi in un array, noi vogliamo che essa possa essere applicata sia a interi, che a reali che a qualunque altro tipo derivato sia necessario.


// ex8_1_3
#include <iostream.h>

typedef int Tipo;

void scambia (Tipo& a, Tipo& b) {
  Tipo temp = a;
  a = b;
  b = temp;
}

void inverti (Tipo* array, int n) {
  for (int i = 0; i < n/2; i++)
    scambia ( array[i], array[n - 1 - i] );
}

void stampa (Tipo* array, int n) {
  for (int i = 0; i < n; i++)
      cout << array[i] << "\t";
  cout << "\n";
}

void main() {
  int n;
  cout << "#elementi? "; cin >> n;
  Tipo* array = new Tipo[n];
  for (int i = 0; i < n; i++)
    array[i] = i+1;
  stampa (array, n);
  inverti (array, n);
  stampa (array, n);
}

output:
 1 2 3 4 5
 5 4 3 2 1

Possiamo in ogni momento modificare il nostro codice, ad esempio utilizzando al posto di typedef int Tipo:


typedef double Tipo;
ed avere le medesime funzione operanti su numeri reali piuttosto che interi. Vedremo in seguito un costrutto del tutto nuovo al C, il template, che ci consentirà di costruire le nostre strutture dati in maniera del tutto indipendente dai tipi dei dati in esse contenuti.


next up previous contents index
Next: Argomenti con valori default Up: Approfondimenti. I files d'intestazione Previous: Approfondimenti. I files d'intestazione   Indice   Indice analitico
Claudio Cicconetti
2000-09-06