2009-07-05 43 views
15

In C++ è possibile creare una struct:Scopo della struct, typedef struct, in C++

struct MyStruct 
{ 
    ... 
} 

E anche possibile effettuare le seguenti operazioni:

typedef struct 
{ 
    ... 
} MyStruct; 

Eppure per quanto io può dire, nessuna differenza percepibile tra i due. Quale è preferibile? Perché esistono entrambi i modi se non c'è differenza? Uno è migliore dell'altro in stile o leggibilità?

+2

Questo è un duplicato di http://stackoverflow.com/questions/612328/difference-between -struct-and-typedef-struct-in-c, ma non ho intenzione di votare per la chiusura perché la risposta accettata a questa domanda è (sottilmente) sbagliata, come spiegato nella risposta secondo-votata ... –

risposta

12

La versione typedef è un caso speciale di

typedef foo bar; 

che definisce una nuova barra "tipo" come alias per foo. Nel tuo caso, foo capita di essere una struttura. In C, questo era l'unico modo per introdurre nuovi "tipi" (tra virgolette, perché non sono realmente equivalenti a int, float e co). In C++, questo non è così utile, perché il C++ è stato progettato per rendere la definizione di nuovi tipi più semplice e completa di C (almeno all'inizio del C++), e il typedef non è nemmeno necessario fare riferimento a una struttura dichiarata in precedenza (o classe).

+1

in questo case foo è anche una struttura senza nome –

+0

Ri ght. e 'MyStruct' sarà usato per scopi di collegamento: Troverete, per esempio, che il compilatore lo userà per maneggiare i nomi delle funzioni membro di esso. –

+0

@David - sì - mentre typedef crea un nome utilizzabile per il tipo senza nome, ci sono conseguenze visibili sull'uso di typedef - vedi la mia risposta per i dettagli :) –

2

Si utilizzerà un typedef in modo che non sia necessario specificare la parola chiave struct quando si dichiarano le variabili di tale struttura.

Senza typedef:

struct MyStruct foo; 

Con typedef:

MyStruct foo; 

Fondamentalmente si stanno facendo MyStruct apparire come un nuovo tipo di modo che implementa anche un certo livello di tipo astrazione come i programmatori non hanno bisogno di sapere esplicitamente di che tipo è. È possibile trasferire MyStruct in una funzione, manipolare i dati in essa contenuti e restituirli e il programmatore non deve mai preoccuparsi di ciò che accade realmente.

Per questo motivo gran parte della libreria standard C utilizza typedef.

+0

quindi solo meno digitando? – darkrain

+5

non c'è bisogno di 'struct' parola chiave in C++, solo C –

+0

Ah scusa, succede sempre quando i programmatori C sono coinvolti in domande C++ :(. Ma hai colto la risposta prima che finissi di modificarlo :) – Cromulent

7

Quest'ultimo è lì per compatibilità con C - utilizzare il primo codice C++ nuovo.

0

La "struct MyStruct {};" costrutto definisce implicitamente il typedef equivalente, quindi tipicamente quello sarebbe l'uso moderno preferito. Ci sono ancora alcuni usi per un typedef, principalmente con i tipi di puntatore alle strutture. Per esempio.

typedef struct MyStruct* MyStructPtr; 
22

Qui ci sono le differenze tra le due dichiarazioni/definizioni:


1) Non è possibile utilizzare un nome typedef per identificare un costruttore o un distruttore

struct MyStruct { MyStruct(); ~MyStruct(); }; // ok 

typedef struct { MyStructTD(); ~MyStructTD(); } MyStructTD; // not ok 

// now consider 
typedef struct MyStruct2 { MyStruct2(); } MyStructTD2; // ok 

MyStructTD2::MyStruct2() { } // ok 
MyStructTD2::MyStructTD2() { } // not ok 

2) Non è possibile nascondere un nome typedef come se fosse possibile nome introdotto tramite la classe-head - o viceversa se hai già una funzione o un oggetto con un certo nome, puoi comunque dichiarare una classe con quel nome usando la classe-head ma non tramite l'approccio typedef.

struct MyStruct { }; // ok 

typedef struct { } MyStructTD; // ok 

void MyStruct() { } // (1) - ok Hides struct MyStruct 
void MyStructTD() { } // (2) - not-ok - ill-formed 

//> Or if you flip it around, consider in a new translation unit: 

void MyStruct() { } // ok 
void MyStructTD() { } // ok 

struct MyStruct { }; // ok 
typedef struct { } MyStructTD; // Not ok 

3) Non è possibile utilizzare un nome typedef in un indicatore di tipo elaborato

struct MyStruct { }; // ok 

typedef struct { } MyStructTD; // ok 

int main() 
{ 
    void MyStruct(); 
    void MyStructTD(); // ok - new declarative region 

    struct MyStruct ms; // ok - names the type 
    struct MyStructTD ms2; // not ok - cannot use typedef-name here 

} 

struct AnotherStruct 
{ 
    friend struct MyStruct; // ok 
    friend struct MyStructTD; // not ok 
}; 

4) Non è possibile utilizzare per definire nidificato structs

struct S { struct M; }; 

typedef struct { } S::M; // not ok 

struct S::M { }; // ok 

Come si può vedere, c'è una differenza visibile tra i due. Alcuni dei capricci di typedef sono il risultato della compatibilità con C (che è principalmente il motivo per cui entrambi i modi esistono credo) - e nella maggior parte dei casi, dichiarare il nome in classe è un C++ più naturale - ha i suoi vantaggi (specialmente quando bisogno di definire costruttori e distruttori), ed è quindi preferibile. Se stai scrivendo un codice che deve essere compatibile con C e C++, allora c'è un vantaggio nell'usare entrambi gli approcci. Ma se stai scrivendo puro C++, trovo che sia più leggibile specificare il nome della classe nella testa della classe.

+0

Wow! Grazie per questo :) – Viet

+0

Un'altra differenza sarebbe nel mangling delle funzioni all'interno di queste strutture o nel riceverle o puntatori a loro come parametri. – CesarB

+0

@CesarB - beh secondo lo standard il nome typedef viene utilizzato per scopi di collegamento se non viene fornito nessun altro nome - quindi non vedo come è diverso - forse è possibile fornire un esempio? –

1

Ci sono molte risposte che considerano entrambi gli approcci come equivalenti, ma non lo sono.

La parola chiave typedef viene utilizzata per creare un alias di tipo, ovvero fornisce un nuovo modo di fare riferimento a un altro tipo. Quando si utilizza typedef struct {} XXX; in realtà si sta creando un tipo senza nome e quindi si crea un alias XXX con quel tipo senza nome. D'altra parte, quando si digita struct XXX {}.

Si prega di leggere la risposta di Michael Burr here (che è una risposta migliore di quella accettata per quella domanda.