In quali scenari è meglio usare a struct
vs a class
in C ++?
In quali scenari è meglio usare a struct
vs a class
in C ++?
Risposte:
Le differenze tra a class
e a struct
in C ++ sono che le strutture hanno public
membri predefiniti e le basi e le classi hanno private
membri e basi predefiniti . Entrambe le classi e le strutture possono avere una miscela di public
, protected
e private
membri, possono utilizzare l'ereditarietà e possono avere funzioni membro.
Consiglierei di usare le strutture come strutture di dati semplici e vecchie senza alcuna caratteristica di classe e di usare le classi come strutture di dati aggregati con private
dati e funzioni membro.
Come tutti gli altri notano, in realtà ci sono solo due differenze linguistiche reali:
struct
valori predefiniti per l'accesso pubblico e class
valori predefiniti per l'accesso privato.struct
impostazione predefinita è l' public
ereditarietà e l' class
impostazione predefinita è l' private
ereditarietà. (Ironia della sorte, come per tante altre cose in C ++, l'impostazione predefinita è al contrario: l' public
ereditarietà è di gran lunga la scelta più comune, ma le persone raramente dichiarano struct
di risparmiare solo digitando la " public
" parola chiave.Ma la vera differenza nella pratica è tra un class
/ struct
che dichiara un costruttore / distruttore e uno che non lo fa. Esistono alcune garanzie per un tipo POD "dati semplici", che non si applicano più una volta acquisita la costruzione della classe. Per mantenere chiara questa distinzione, molte persone usano deliberatamente struct
s solo per i tipi POD e, se stanno per aggiungere metodi, usano class
es. In caso contrario, la differenza tra i due frammenti non ha senso:
class X
{
public:
// ...
};
struct X
{
// ...
};
(Per inciso, ecco un thread con alcune buone spiegazioni su cosa significhi effettivamente "tipo POD": cosa sono i tipi POD in C ++? )
struct
o class
non ha alcuna influenza sul fatto che il proprio oggetto sia POD o se si debba definire un costruttore / distruttore di copie. Anche le funzioni membro non influiscono su qualcosa che è POD. Mentre rileggo quello che hai scritto, vedo che non stai suggerendo diversamente, ma l'attuale formulazione è confusa
Ci sono molte idee sbagliate nelle risposte esistenti.
Entrambi class
e struct
dichiarano una classe.
Sì, potrebbe essere necessario riorganizzare le parole chiave modificando l'accesso all'interno della definizione della classe, a seconda della parola chiave utilizzata per dichiarare la classe.
Ma, al di là della sintassi, l' unica ragione per scegliere l'una rispetto all'altra è la convenzione / stile / preferenza.
Ad alcune persone piace attenersi alla struct
parola chiave per le classi senza funzioni membro, perché la definizione risultante "sembra" una struttura semplice da C.
Allo stesso modo, ad alcune persone piace usare la class
parola chiave per le classi con funzioni e private
dati dei membri , perché dice "classe" su di essa e quindi sembra esempi dal loro libro preferito sulla programmazione orientata agli oggetti.
La realtà è che questo dipende completamente da te e dal tuo team, e non farà letteralmente alcuna differenza per il tuo programma.
Le seguenti due classi sono assolutamente equivalenti in ogni modo tranne il loro nome:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
Puoi anche cambiare le parole chiave durante la redeclaration:
class Foo;
struct Bar;
(anche se questo rompe le build di Visual Studio a causa della non conformità, in modo che il compilatore emetterà un avviso quando lo fai.)
e le seguenti espressioni valutano entrambe come vere:
std::is_class<Foo>::value
std::is_class<Bar>::value
Si noti, tuttavia, che non è possibile cambiare le parole chiave durante la ridefinizione ; questo solo perché (secondo la regola di una definizione) le definizioni di classe duplicate tra le unità di traduzione devono "consistere nella stessa sequenza di token" . Questo significa che non puoi nemmeno scambiarti const int member;
con int const member;
, e non ha nulla a che fare con la semantica di class
o struct
.
class foo { public: ... };
e un'altra può avere struct foo { ... };
che dovrebbe valere secondo l'affermazione "assolutamente equivalente". Viene alla ragione che le dichiarazioni incomplete struct foo;
e class foo;
sono intercambiabili. Questi non specificano il corpo della classe e quindi non parlano nulla al layout di accesso.
Foo
e Bar
sono ancora tipi equivalenti / identici. Mi sono assicurato di dire "quando redeclaring " e dare un esempio. Vieni a pensarci bene, lo chiarirò nella risposta per assicurarmi di non fuorviare le persone in UB
L'unica volta che utilizzo una struttura anziché una classe è quando dichiaro un funzione subito prima di usarlo in una chiamata di funzione e voglio minimizzare la sintassi per motivi di chiarezza. per esempio:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
Dalla FAQ Lite C ++ :
I membri e le classi di base di uno struct sono pubblici per impostazione predefinita, mentre in classe sono automaticamente privati. Nota: è necessario rendere le classi di base esplicitamente pubbliche, private o protette, anziché fare affidamento sui valori predefiniti.
struct e class sono altrimenti funzionalmente equivalenti.
OK, abbastanza di quel discorso techno perfettamente pulito. Emotivamente, la maggior parte degli sviluppatori fa una forte distinzione tra una classe e una struttura. Una struttura sembra semplicemente una pila aperta di bit con molto poco in termini di incapsulamento o funzionalità. Una classe si sente come un membro vivente e responsabile della società con servizi intelligenti, una forte barriera di incapsulamento e un'interfaccia ben definita. Dal momento che questa è la connotazione che molte persone hanno già, probabilmente dovresti usare la parola chiave struct se hai una classe che ha pochissimi metodi e ha dati pubblici (cose del genere esistono in sistemi ben progettati!), Ma altrimenti dovresti probabilmente usare la classe parola chiave.
Un posto in cui una struttura mi è stata utile è quando ho un sistema che riceve messaggi in formato fisso (ad esempio una porta seriale) da un altro sistema. È possibile eseguire il cast del flusso di byte in una struttura che definisce i campi e quindi accedere facilmente ai campi.
typedef struct
{
int messageId;
int messageCounter;
int messageData;
} tMessageType;
void processMessage(unsigned char *rawMessage)
{
tMessageType *messageFields = (tMessageType *)rawMessage;
printf("MessageId is %d\n", messageFields->messageId);
}
Ovviamente, questa è la stessa cosa che faresti in C, ma trovo che l'overhead di dover decodificare il messaggio in una classe di solito non ne valga la pena.
operator >>
una classe invece di scrivere la processMessage
funzione, il che renderebbe il tuo C ++ più simile al C ++ corretto e meno al C.
__packed__
struttura e disporre di un implementaion ifdef compatibile con endian (è necessario capovolgere l'ordine su una macchina in cui l'endianess è opposta a quella dell'origine dati esterna sta fornendo). Non è carino, ma ho usato per comprimere / decomprimere i registri per periferiche remote su piattaforme integrate in modo portatile.
char
tipo, che sono esenti da aliasing. Tuttavia, c'è ancora un problema, sebbene diverso: se si esegue il cast char*
di un tipo diverso, se in realtà non vi era alcun oggetto di quest'ultimo tipo già inizializzato a quell'indirizzo, è UB in quanto viola le regole di vita. Dopo tutto, anche se il tipo di destinazione è banalmente costruibile, la sola allocazione di memoria non è sufficiente per C ++ per consentire formalmente di trattare quella memoria come quel tipo.
Puoi usare "struct" in C ++ se stai scrivendo una libreria i cui interni sono C ++ ma l'API può essere chiamata con il codice C o C ++. È sufficiente creare una singola intestazione che contenga strutture e funzioni API globali esposte al codice C e C ++ in questo modo:
// C access Header to a C++ library
#ifdef __cpp
extern "C" {
#endif
// Put your C struct's here
struct foo
{
...
};
// NOTE: the typedef is used because C does not automatically generate
// a typedef with the same name as a struct like C++.
typedef struct foo foo;
// Put your C API functions here
void bar(foo *fun);
#ifdef __cpp
}
#endif
Quindi puoi scrivere una barra delle funzioni () in un file C ++ usando il codice C ++ e renderla richiamabile da C e i due mondi possono condividere i dati attraverso le strutture dichiarate. Naturalmente ci sono altri avvertimenti quando si mescolano C e C ++ ma questo è un esempio semplificato.
Come tutti dicono, l'unica vera differenza è l'accesso predefinito. Ma uso particolarmente struct quando non desidero alcun tipo di incapsulamento con una semplice classe di dati, anche se implemento alcuni metodi di supporto. Ad esempio, quando ho bisogno di qualcosa del genere:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
Per rispondere alla mia domanda (spudoratamente), Come già accennato, i privilegi di accesso sono l'unica differenza tra loro in C ++.
Tendo a usare una struttura solo per l'archiviazione dei dati. Gli permetterò di ottenere alcune funzioni di aiuto se semplifica il lavoro con i dati. Tuttavia, non appena i dati richiedono il controllo del flusso (ovvero getter / setter che mantengono o proteggono uno stato interno) o iniziano ad acquisire qualsiasi funzionalità principale (sostanzialmente più simile ad un oggetto), verranno "aggiornati" a una classe per comunicare meglio l'intento.
Le strutture ( POD , più in generale) sono utili quando si fornisce un'interfaccia C-compatibile con un'implementazione C ++, poiché sono trasportabili attraverso i confini del linguaggio e i formati di linker.
Se questo non ti riguarda, suppongo che l'uso di "struct" invece di "class" sia un buon comunicatore di intenti (come ha detto @ZeroSignal sopra). Le strutture hanno anche una semantica di copia più prevedibile, quindi sono utili per i dati che intendi scrivere su supporti esterni o inviare attraverso il filo.
Le strutture sono utili anche per varie attività di metaprogrammazione, come modelli di tratti che espongono solo un mucchio di typedef dipendenti:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
... Ma questo sta davvero sfruttando il livello di protezione predefinito di struct essendo pubblico ...
Per C ++, non c'è davvero molta differenza tra le strutture e le classi. La principale differenza funzionale è che i membri di una struttura sono pubblici per impostazione predefinita, mentre sono privati per impostazione predefinita nelle classi. Altrimenti, per quanto riguarda la lingua, sono equivalenti.
Detto questo, tendo a usare le strutture in C ++ come faccio in C #, in modo simile a quello che ha detto Brian. Le strutture sono semplici contenitori di dati, mentre le classi vengono utilizzate per gli oggetti che devono agire sui dati oltre a limitarsi a trattenerli.
Sono praticamente la stessa cosa. Grazie alla magia del C ++, una struttura può contenere funzioni, usare l'ereditarietà, creata usando "nuovo" e così via proprio come una classe
L'unica differenza funzionale è che una classe inizia con diritti di accesso privati, mentre una struttura inizia con pubblico. Questa è la compatibilità retroattiva con C.
In pratica, ho sempre usato le strutture come supporti dati e le classi come oggetti.
Come altri hanno sottolineato
C'è una chiara raccomandazione su quando usare quali da Stroustrup / Sutter:
Tuttavia, tieni presente che non è saggio inoltrare la dichiarazione sth. come classe ( class X;
) e definirlo come struct ( struct X { ... }
). Potrebbe funzionare su alcuni linker (ad esempio, g ++) e potrebbe fallire su altri (ad esempio, MSVC), quindi ti ritroverai all'inferno degli sviluppatori.
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
non solo si compila e funziona con MSVC 2017, ma produce anche un chiaro avvertimento che è Foo
stato dichiarato come struct
ma definito come class
. Ma ricordo anche chiaramente che è costato mezza giornata alla nostra squadra trovare quello stupido insetto. Non sono sicuro di quale versione MSVC abbiamo usato allora.
class
o struct
su una dichiarazione in avanti, e i due sono liberamente intercambiabili secondo lo standard (anche se è noto che VS avverte; ho sempre pensato che fosse solo per evitare apparenti errori del programmatore). Qualcosa non ha odore proprio qui. Sei sicuro che non sia stato un bug di violazione ODR?
struct
-forward a class
-forwards, i problemi sono scomparsi. Ad oggi lo trovo anche strano. Sarei felice se potessi far luce su di esso.
I membri della classe sono privati per impostazione predefinita.
class test_one {
int main_one();
};
È equivalente a
class test_one {
private:
int main_one();
};
Quindi se ci provi
int two = one.main_one();
Avremo un errore: main_one is private
perché non è accessibile. Possiamo risolverlo inizializzandolo specificando che è pubblico cioè
class test_one {
public:
int main_one();
};
Una struttura è una classe in cui i membri sono pubblici per impostazione predefinita.
struct test_one {
int main_one;
};
Il mezzo main_one
è privato cioè
class test_one {
public:
int main_one;
};
Uso le strutture per le strutture di dati in cui i membri possono assumere qualsiasi valore, in questo modo è più semplice.
Un vantaggio di struct
over class
è che salva una riga di codice, se aderisce ai "primi membri pubblici, quindi privati". In questa luce, trovo la parola chiave class
inutile.
Ecco un altro motivo per usare solo struct
e mai class
. Alcune linee guida sullo stile di codice per C ++ suggeriscono l'uso di lettere minuscole per le macro di funzioni, la logica è che quando la macro viene convertita in una funzione incorporata, non è necessario modificare il nome. Anch'io. Hai la tua bella struttura in stile C e un giorno scoprirai che devi aggiungere un costruttore o un metodo di convenienza. Lo cambi in un class
? Ovunque?
Distinguere tra se struct
e class
es è troppo fastidioso, mettendosi in cammino nel fare ciò che dovremmo fare - la programmazione. Come molti dei problemi di C ++, nasce dal forte desiderio di compatibilità con le versioni precedenti.
class
? Pensavi che una classe definita con la struct
parola chiave non potesse avere funzioni membro o un costruttore?
joe()
deve essere definita con una class
parola chiave? Ogni classe con almeno 4 int
membri deve essere definita con una struct
parola chiave?
struct
, gli aggregati con metodi sono definiti con class
". Troppa seccatura.
sono la stessa cosa con impostazioni predefinite diverse (private per impostazione predefinita class
e public per impostazione predefinita per struct
), quindi in teoria sono totalmente intercambiabili.
quindi, se voglio solo impacchettare alcune informazioni per spostarmi, uso uno struct, anche se ho messo alcuni metodi lì (ma non molti). Se è una cosa per lo più opaca, in cui l'uso principale sarebbe tramite metodi e non direttamente ai membri dei dati, utilizzo una classe completa.
Entrambi struct
e class
sono gli stessi sotto il cofano, sebbene con impostazioni predefinite diverse per quanto riguarda la visibilità, il struct
valore predefinito è pubblico e il class
valore predefinito è privato. È possibile modificare l'uno e l'altro con l'uso appropriato di private
e public
. Entrambi consentono ereditarietà, metodi, costruttori, distruttori e tutto il resto delle chicche di un linguaggio orientato agli oggetti.
Tuttavia una grande differenza tra i due è che struct
come parola chiave è supportata in C mentre class
non lo è. Questo significa che si può usare un struct
in un includono file che può essere #include
in o C ++ o C fino a quando il struct
è uno stile C pianura struct
e tutto il resto del include file è compatibile con C, vale a dire senza C ++ parole chiave specifiche, come private
, public
, no metodi, nessuna eredità, ecc. ecc. ecc.
Lo stile CA struct
può essere utilizzato con altre interfacce che supportano l'utilizzo dello stile C struct
per trasportare i dati avanti e indietro sull'interfaccia.
Lo stile CA struct
è un tipo di modello (non un modello C ++ ma piuttosto un modello o uno stencil) che descrive il layout di un'area di memoria. Nel corso degli anni interfacce utilizzabili da C e C con i plug-in (qui sta guardando a voi Java e Python e Visual Basic) sono stati creati alcuni dei quali lavoro con stile C struct
.
Tecnicamente entrambi sono gli stessi in C ++ - per esempio è possibile che uno struct abbia operatori sovraccaricati, ecc.
Però :
Uso le strutture quando desidero passare simultaneamente informazioni di più tipi. Uso le classi quando ho a che fare con un oggetto "funzionale".
Spero che sia d'aiuto.
#include <string>
#include <map>
using namespace std;
struct student
{
int age;
string name;
map<string, int> grades
};
class ClassRoom
{
typedef map<string, student> student_map;
public :
student getStudentByName(string name) const
{ student_map::const_iterator m_it = students.find(name); return m_it->second; }
private :
student_map students;
};
Ad esempio, sto restituendo uno studente struct nei metodi get ... () qui - divertiti.
Quando sceglieresti di usare struct e quando usare la classe in C ++?
Uso struct
quando definisco functors
e POD
. Altrimenti lo uso class
.
// '()' is public by default!
struct mycompare : public std::binary_function<int, int, bool>
{
bool operator()(int first, int second)
{ return first < second; }
};
class mycompare : public std::binary_function<int, int, bool>
{
public:
bool operator()(int first, int second)
{ return first < second; }
};
std::binary_function<>
non è solo deprecata, c ++ 17 la rimuove persino.
Tutti i membri della classe sono privati per impostazione predefinita e tutti i membri della struttura sono pubblici per impostazione predefinita. La classe ha basi private predefinite e Struct ha basi pubbliche predefinite. Struct nel caso di C non può avere funzioni membro dove come nel caso di C ++ possiamo aggiungere funzioni membro alla struttura. A parte queste differenze, non trovo nulla di sorprendente su di loro.
Uso struct solo quando devo conservare alcuni dati senza alcuna funzione membro associata (per operare sui dati dei membri) e accedere direttamente alle variabili dei dati.
Ad esempio: Lettura / Scrittura di dati da file e stream di socket ecc. Passaggio di argomenti di funzioni in una struttura in cui gli argomenti di funzione sono troppi e la sintassi della funzione sembra troppo lunga.
Tecnicamente non c'è grande differenza tra classe e struttura tranne l'accessibilità di default. Inoltre dipende dallo stile di programmazione come lo usi.
Ho pensato che Structs fosse inteso come una struttura di dati (come una matrice di informazioni di tipo multi-data) e che le classi fossero intese per il pacchetto di codice (come raccolte di subroutine e funzioni).
:(
Non uso mai "struct" in C ++.
Non riesco mai a immaginare uno scenario in cui useresti una struttura quando desideri membri privati, a meno che tu non stia volontariamente cercando di confondere.
Sembra che usare le strutture sia più un'indicazione sintattica di come verranno usati i dati, ma preferirei semplicemente creare una classe e provare a renderla esplicita nel nome della classe, o attraverso commenti.
Per esempio
class PublicInputData {
//data members
};
struct
già abbastanza esplicito che i membri della classe saranno, per impostazione predefinita, pubblici?