[C++]Dubbi su costrutto Typedef
Non mi sono chiare alcune cose:
perchè si usa,qual è è la sua utilità(è opzionale o ci sono casi in cui si DEVE usare)?
Con questo costrutto l'utente dichiara un nuovo tipo,giusto?Io so che i tipi esistenti sono int,char,float,ecc...,ma allora l'utente come fa a creare nuovi tipi che poi possono essere riconosciuti dalla macchina?
Premessa:sto studiando il costrutto nell'ambito degli array
Ad esempio,avere
perchè si usa,qual è è la sua utilità(è opzionale o ci sono casi in cui si DEVE usare)?
Con questo costrutto l'utente dichiara un nuovo tipo,giusto?Io so che i tipi esistenti sono int,char,float,ecc...,ma allora l'utente come fa a creare nuovi tipi che poi possono essere riconosciuti dalla macchina?
Premessa:sto studiando il costrutto nell'ambito degli array
Ad esempio,avere
int matrice[3][3]è molto diverso da avere
typedef int matrice[3][3]?
Risposte
In C++ abbiamo tipi complessi a differenza del Java (Template ti dice nulla) infatti in C++ abbiamo typedef in Java no (ancora per poco, magari poi lo aggiungeranno anche in Java chissà)?
Quindi abbiamo ad esempio una lista di oggetti (std::list)
Gli oggetti possono essere biciclette, banane, sassolini
allora avremo diversi tipi
std::list lista1;
std::list lista2;
std::list lista3;
a questo punto facciamo un typedef e abbreviamo la scrittura della dichiarazione delle liste.
Così se dovessimo usare una lista di biciclette ci basterebbe scrivere
ListaBici lista1;
Oppure se facciamo il typedef di una lista di liste di bici
anziché scrivere
std::list< std::list > lista1;
scriviamo
ListaListaBici lista1;
Ovviamente come ogni funzionalità pensata per un utilizzo particolare c'è chi "abusa" di essa e per esempio troverai qualcuno che anzichè scrivere
unsigned int a;
scriverà
Uint a;
Spero di essere stato esaustivo.
Quindi abbiamo ad esempio una lista di oggetti (std::list)
Gli oggetti possono essere biciclette, banane, sassolini
allora avremo diversi tipi
std::list
std::list
std::list
a questo punto facciamo un typedef e abbreviamo la scrittura della dichiarazione delle liste.
Così se dovessimo usare una lista di biciclette ci basterebbe scrivere
ListaBici lista1;
Oppure se facciamo il typedef di una lista di liste di bici
anziché scrivere
std::list< std::list
scriviamo
ListaListaBici lista1;
Ovviamente come ogni funzionalità pensata per un utilizzo particolare c'è chi "abusa" di essa e per esempio troverai qualcuno che anzichè scrivere
unsigned int a;
scriverà
Uint a;
Spero di essere stato esaustivo.
ehm,non tanto.Non ho conoscenze di Java,e inoltre non so che significa loa scrittura std::list< > ...
Scusa me allora XD.
Lo scopo originale del Typedef è proprio quello di facilitare la vita al programmatore.
Laddove c'è una variabile/oggetto "A" e il suo tipo è "UnTipoMoltoLungoDaScriverePercheQualcunoLHaScrittoCosì"
con un typedef è possibile abbreviare la scrittura del tipo della variabile/oggetto ad un semplice "TipoLungo".
A seconda dell'applicazione puoi crearti te un typedef che velocizza la scrittura del programma (nel tuo esempio puoi ad esempio chiamare una matrice 3x3 di interi come "mat3x3" che è molto più veloce da scrivere rispetto a "int Matrice[3][3]".)
Lo scopo principale comunque è quello di rendere il programma più leggibile e meno confuso. Ad esempio se accorci troppo "mat3x3" e lo fai diventare "m33" potrebbe diventare incomprensibile per chi legge il programma.
L'aggiunta di typedef non è comunque una scelta leggera in quanto se usi 200 typedef non potresti mai ricordarli tutti e comunque ogni programmatore segue una sua logica per scegliere il nome giusto da dare con un typedef.
Edit:
http://it.wikipedia.org/wiki/Typedef
Lo scopo originale del Typedef è proprio quello di facilitare la vita al programmatore.
Laddove c'è una variabile/oggetto "A" e il suo tipo è "UnTipoMoltoLungoDaScriverePercheQualcunoLHaScrittoCosì"
con un typedef è possibile abbreviare la scrittura del tipo della variabile/oggetto ad un semplice "TipoLungo".
A seconda dell'applicazione puoi crearti te un typedef che velocizza la scrittura del programma (nel tuo esempio puoi ad esempio chiamare una matrice 3x3 di interi come "mat3x3" che è molto più veloce da scrivere rispetto a "int Matrice[3][3]".)
Lo scopo principale comunque è quello di rendere il programma più leggibile e meno confuso. Ad esempio se accorci troppo "mat3x3" e lo fai diventare "m33" potrebbe diventare incomprensibile per chi legge il programma.
L'aggiunta di typedef non è comunque una scelta leggera in quanto se usi 200 typedef non potresti mai ricordarli tutti e comunque ogni programmatore segue una sua logica per scegliere il nome giusto da dare con un typedef.
Edit:
http://it.wikipedia.org/wiki/Typedef
Ma i valori che può assumere sono sempre i soliti giusto?(int,char,float...),non è che si "creano" dal nulla altri tipi(a sentire il libro sembra quasi così)
No. C++ è un linguaggio Object-Oriented. Quindi i tipi possono essere Oggetti.
Se qualcuno scrive una classe che si chiama "Automobile" tu puoi avere "Automobile" come tipo.. Automobile non è ne un "int" ne un "char" ma è un "Automobile". Per questo motivo penso sia meglio iniziare con il C che con il C++ (cosa molto comune nella didattica odierna che svilisce così il C che rimane comunque tra i linguaggi più usati assieme a Java e C++).
Ovviamente tu puoi crearti Array con i Typedef
Ad esempio
typedef int[4] data; //giorno, mese, anno, ora
typedef char[255] titolo; // il titolo può contenere al massimo 255 caratteri
in questo modo puoi usare il tipo "titolo" che tu sai gia che in realtà si tratta di un array di char di lunghezza prefissata.
inoltre se un giorno qualcuno fa così
typedef char[255] url; //indirizzo di un sito internet
tu sai che quanto lui scrive "url" intende proprio l'indirizzo internet così non lo confondi con il titolo del libro (visto che entrambi sono char[255]);
ovviamente puoi anche creare degli "struct" con un nome e poi chiamarli con un altro nome. (ad esempio se pensi che "data" sia poco chiaro puoi chiamarlo di nuovo in un altro modo)
typedef data DayMonthYearHour;
Sono cose che si capisono meglio dopo qualche mese di programmazione attiva. Perchè se ne comprende meglio l'utilità "in opera" che teoricamente.
Comunque personalmente non mi piace usare il typedef in C. Lo trovo molto più utile con i template del C++ (che tu però non conosci ancora. spero solo di non averti confuso).
Se qualcuno scrive una classe che si chiama "Automobile" tu puoi avere "Automobile" come tipo.. Automobile non è ne un "int" ne un "char" ma è un "Automobile". Per questo motivo penso sia meglio iniziare con il C che con il C++ (cosa molto comune nella didattica odierna che svilisce così il C che rimane comunque tra i linguaggi più usati assieme a Java e C++).
Ovviamente tu puoi crearti Array con i Typedef
Ad esempio
typedef int[4] data; //giorno, mese, anno, ora
typedef char[255] titolo; // il titolo può contenere al massimo 255 caratteri
in questo modo puoi usare il tipo "titolo" che tu sai gia che in realtà si tratta di un array di char di lunghezza prefissata.
inoltre se un giorno qualcuno fa così
typedef char[255] url; //indirizzo di un sito internet
tu sai che quanto lui scrive "url" intende proprio l'indirizzo internet così non lo confondi con il titolo del libro (visto che entrambi sono char[255]);
ovviamente puoi anche creare degli "struct" con un nome e poi chiamarli con un altro nome. (ad esempio se pensi che "data" sia poco chiaro puoi chiamarlo di nuovo in un altro modo)
typedef data DayMonthYearHour;
Sono cose che si capisono meglio dopo qualche mese di programmazione attiva. Perchè se ne comprende meglio l'utilità "in opera" che teoricamente.
Comunque personalmente non mi piace usare il typedef in C. Lo trovo molto più utile con i template del C++ (che tu però non conosci ancora. spero solo di non averti confuso).
"Vitalluni":
Sono cose che si capisono meglio dopo qualche mese di programmazione attiva. Perchè se ne comprende meglio l'utilità "in opera" che teoricamente.
Eh...me ne rendo perfettamente conto.Se non fosse che tra due mesi ho già l'esame.
Secondo voi si può sostenere un esame di programmazione con soli 3 mesi di "studio" autonomo(perchè il prof dà tutto per scontato) ,senza avere basi di informatica di alcun tipo(perchè non l'ho fatta al liceo) e senza avere abbastanza tempo per le esercitazioni(perchè ho altri e due esami)?
Puoi riuscirci se entri nella mentalità giusta.
Io quando ho dato il mio primo esame di C non avevo esperienza di programmazione (mai programmato al liceo) e stavo preparando altri esami. Me la sono cavata al primo tentativo con un 24 (anche se poi ho dovuto ridare un altro esame che non ho passato). Ad altri è andata peggio (eppure programmavano già.. o almeno dicevano così).
Le esercitazioni sono essenziali. Visto che normalmente non vengono ripetute conviene farle tutte e dedicarci tempo. Magari puoi fare le esercitazioni e rimandare di un appello l'esame (ma anche li dipende da quali sono le procedure per l'esame che variano da professore a professore), ma saltare le esercitazione è controproducente(visto che normalmente fanno parte della valutazione).
Se proprio non riesci a gestire tutti questi esami contemporaneamente ti conviene guardare quali sono gli esami che ti servono di più per il prossimo anno (ad esempio se ti serve l'esame di Programmazione perchè è propedeutico ti conviene evitare di rimandarlo troppo. Perchè rimandando gli esami le conoscenze "fresche" vengono dimenticate e poi ti trovi in difficoltà perchè il tempo passa e le lezioni si affievoliscono nella memoria. Anche se normalmente quando si impara a programmare si continua a programmare quindi la programmazione è difficile che si scordi se si diventa appassionati).
Io quando ho dato il mio primo esame di C non avevo esperienza di programmazione (mai programmato al liceo) e stavo preparando altri esami. Me la sono cavata al primo tentativo con un 24 (anche se poi ho dovuto ridare un altro esame che non ho passato). Ad altri è andata peggio (eppure programmavano già.. o almeno dicevano così).
Le esercitazioni sono essenziali. Visto che normalmente non vengono ripetute conviene farle tutte e dedicarci tempo. Magari puoi fare le esercitazioni e rimandare di un appello l'esame (ma anche li dipende da quali sono le procedure per l'esame che variano da professore a professore), ma saltare le esercitazione è controproducente(visto che normalmente fanno parte della valutazione).
Se proprio non riesci a gestire tutti questi esami contemporaneamente ti conviene guardare quali sono gli esami che ti servono di più per il prossimo anno (ad esempio se ti serve l'esame di Programmazione perchè è propedeutico ti conviene evitare di rimandarlo troppo. Perchè rimandando gli esami le conoscenze "fresche" vengono dimenticate e poi ti trovi in difficoltà perchè il tempo passa e le lezioni si affievoliscono nella memoria. Anche se normalmente quando si impara a programmare si continua a programmare quindi la programmazione è difficile che si scordi se si diventa appassionati).
typedef è nato nel C e quindi il suo scopo va cercato lì e non nel C++ in cui ha comunque acquisito nuovi usi (che presenterò più avanti).
Una delle ragioni per cui typedef era usato in C era quello di permettere di chiamare comodamente strutture, union e enumerazioni che in C non avevano un vero e proprio nome. Non a caso K&R definisce il typedef nel capitolo sulle struct (che in C++ sono state spesso soppiantate della classi).
Per esempio supponiamo di avere la struttura scritta come:
allora nel main dichiaravi una struttura di tipo point come:
e non
come sarebbe più comodo (e come scrivi in C++).
Quindi era uso comune definire la struttura come
o metodi equivalenti.
Cito il K&R riguardo allo scopo del typedef:
Questi sono ancora i maggiori usi del typedef anche se l'uso come parametrizzazione ha anche un secondo fine: la programmazione generica.
Seppur in C la programmazione generica fosse affidata principalmente a trucchetti di altro tipo (il C++ ne ha di nuovi e migliori) l'uso di typedef permette comunque di scrivere, senza troppi trucchi, una libreria che può essere adattata ai tuoi scopi con pochi cambiamenti (anche se non si possono usare tipi diversi in uno stesso programma). La struttura di prima, per esempio, non subiva modifiche sostanziali se al posto di float avessi usato double, int o qualche un tipo complesso. L'usare il typedef mi avrebbe potuto quindi permettere di cambiare quel tipo cambiando una sola parola. Per quanto questo non sia, in C++, il metodo migliore.
Riguardo alla seconda ragione presentata dal K&R evidenzierei che inoltre l'uso del typedef ti è utile per mascherare la struttura che ci sta dietro al tipo in questione. Questo aspetto non era però sufficientemente presente in C in quanto il C non possiede l'overloading di funzioni e/o operatori. Quindi l'uso del typedef è molto più limitato che in C++. Per esempio nel caso sopra il cambio sarebbe stato possibile finché ti limitavi a fare somme e prodotti per scalari ma per esempio avevi problemi se cercavi di usare le funzioni di math.h (in C++ è più conosciuta come cmath).
In C++ con l'overloarding di funzioni e operatori il typedef ti permette spesso di dimenticarti da che tipo sei partito purché le funzioni che chiami possiedano una specializzazione per quel tipo.
Un uso "nuovo" che ha il typedef è legato ai template. Non sono però sicuro che tu conosca abbastanza il C++ per spiegartelo bene. In parole povere i template servono per fare funzioni che funzionano su qualsiasi oggetto che possiede una interfaccia sufficientemente compatibile con certi tipi di riferimento. Ogni tanto hai però bisogno di far riferimento ad un certo tipo che viene usato da quell'oggetto. In alcuni casi non ti è possibile creare più versioni e puoi richiedere che l'oggetto sia esso stesso a darti il tipo utilizzando un typedef. Non so se mi sono spiegato bene. Ma anche farti un esempio pratico (anche se ce l'ho in mente perché mi è capitato in un progetto recente) se tu non sai cosa sono i tamplate mi pare un po' complicato.
Una delle ragioni per cui typedef era usato in C era quello di permettere di chiamare comodamente strutture, union e enumerazioni che in C non avevano un vero e proprio nome. Non a caso K&R definisce il typedef nel capitolo sulle struct (che in C++ sono state spesso soppiantate della classi).
Per esempio supponiamo di avere la struttura scritta come:
struct point { float x,y,z; };
allora nel main dichiaravi una struttura di tipo point come:
struct point p;
e non
point p;
come sarebbe più comodo (e come scrivi in C++).
Quindi era uso comune definire la struttura come
typedef struct point { float x,y,z; };
o metodi equivalenti.
Cito il K&R riguardo allo scopo del typedef:
"K&R":
Besides purely aesthetic issues, there are two main reasons for using typedefs. The first is to parameterize a program against portability problems. If typedefs are used for data types that may be machine-dependent, only the typedefs need change when the program is moved. One common situation is to use typedef names for various integer quantities, then make an appropriate set of choices of short, int, and long for each host machine. Types like size_t and ptrdiff_t from the standard library are examples.
The second purpose of typedefs is to provide better documentation for a program - a type called Treeptr may be easier to understand than one declared only as a pointer to a complicated structure.
Questi sono ancora i maggiori usi del typedef anche se l'uso come parametrizzazione ha anche un secondo fine: la programmazione generica.
Seppur in C la programmazione generica fosse affidata principalmente a trucchetti di altro tipo (il C++ ne ha di nuovi e migliori) l'uso di typedef permette comunque di scrivere, senza troppi trucchi, una libreria che può essere adattata ai tuoi scopi con pochi cambiamenti (anche se non si possono usare tipi diversi in uno stesso programma). La struttura di prima, per esempio, non subiva modifiche sostanziali se al posto di float avessi usato double, int o qualche un tipo complesso. L'usare il typedef mi avrebbe potuto quindi permettere di cambiare quel tipo cambiando una sola parola. Per quanto questo non sia, in C++, il metodo migliore.
Riguardo alla seconda ragione presentata dal K&R evidenzierei che inoltre l'uso del typedef ti è utile per mascherare la struttura che ci sta dietro al tipo in questione. Questo aspetto non era però sufficientemente presente in C in quanto il C non possiede l'overloading di funzioni e/o operatori. Quindi l'uso del typedef è molto più limitato che in C++. Per esempio nel caso sopra il cambio sarebbe stato possibile finché ti limitavi a fare somme e prodotti per scalari ma per esempio avevi problemi se cercavi di usare le funzioni di math.h (in C++ è più conosciuta come cmath).
In C++ con l'overloarding di funzioni e operatori il typedef ti permette spesso di dimenticarti da che tipo sei partito purché le funzioni che chiami possiedano una specializzazione per quel tipo.
Un uso "nuovo" che ha il typedef è legato ai template. Non sono però sicuro che tu conosca abbastanza il C++ per spiegartelo bene. In parole povere i template servono per fare funzioni che funzionano su qualsiasi oggetto che possiede una interfaccia sufficientemente compatibile con certi tipi di riferimento. Ogni tanto hai però bisogno di far riferimento ad un certo tipo che viene usato da quell'oggetto. In alcuni casi non ti è possibile creare più versioni e puoi richiedere che l'oggetto sia esso stesso a darti il tipo utilizzando un typedef. Non so se mi sono spiegato bene. Ma anche farti un esempio pratico (anche se ce l'ho in mente perché mi è capitato in un progetto recente) se tu non sai cosa sono i tamplate mi pare un po' complicato.
Solo per mostrare i problemi insiti con l'uso del typedef con gli array con cui io personalmente sconsiglio vivamente l'uso (se proprio vuoi quel tipo allora crea una struttura o una classe) ho scritto il seguente codice che non compila proprio perché typedef non definisce un nuovo tipo.
Ho usato Cameau C++ online per compilarlo e il codice non è un estratto di bellezza ne troppo corretto se quello che volevi fare era una funzione di massimo. Cameau dà i seguenti errori:
#include <iostream> using namespace std; typedef int T[2]; typedef int T2[4]; int Max(T2 const); int Max(T const); int main() { T uno = {1, 2}; T2 due = {1, 2, 3, 4}; cout << Max(uno) << endl; cout << Max(due) << endl; return 0; } int Max(T2 const c) { int ret=0; for(int i=0; i<4; ++i) { if(ret<c[i]) ret = c[i]; } return ret; } int Max(T const c) { int ret=0; for(int i=0; i<2; ++i) { if(ret<c[i]) ret = c[i]; } return ret; }
Ho usato Cameau C++ online per compilarlo e il codice non è un estratto di bellezza ne troppo corretto se quello che volevi fare era una funzione di massimo. Cameau dà i seguenti errori:
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions
"ComeauTest.c", line 30: error: function "Max" has already been defined
int Max(T const c)
^
1 error detected in the compilation of "ComeauTest.c".