Dans quels scénarios vaut-il mieux utiliser un struct
vs un class
en C ++?
Dans quels scénarios vaut-il mieux utiliser un struct
vs un class
en C ++?
Réponses:
Les différences entre a class
et a struct
en C ++ sont que les structures ont des public
membres et des bases par défaut et que les classes ont des private
membres et des bases par défaut . Les deux classes et structs peuvent avoir un mélange de public
, protected
et les private
membres peuvent utiliser l' héritage et peuvent avoir des fonctions membres.
Je recommanderais d'utiliser des structures en tant que structures de données anciennes sans aucune fonctionnalité de classe, et d'utiliser des classes en tant que structures de données agrégées avec des private
données et des fonctions membres.
Comme tout le monde le note, il n'y a vraiment que deux différences linguistiques réelles:
struct
par défaut à l'accès public et par class
défaut à l'accès privé.struct
défaut à l' public
héritage et par class
défaut à l' private
héritage. (Ironiquement, comme avec tant de choses en C ++, la valeur par défaut est à l'envers: l' public
héritage est de loin le choix le plus courant, mais les gens déclarent rarement struct
s juste pour économiser en tapant le public
mot-clé " ".Mais la vraie différence dans la pratique est entre un class
/ struct
qui déclare un constructeur / destructeur et un qui ne le fait pas. Il existe certaines garanties pour un type de POD "plain-old-data", qui ne s'appliquent plus une fois que vous avez repris la construction de la classe. Pour garder cette distinction claire, de nombreuses personnes utilisent délibérément uniquement struct
s pour les types POD et, si elles veulent ajouter des méthodes, utilisez class
es. La différence entre les deux fragments ci-dessous est par ailleurs dénuée de sens:
class X
{
public:
// ...
};
struct X
{
// ...
};
(Par ailleurs, voici un fil avec de bonnes explications sur ce que signifie réellement "type POD": Que sont les types POD en C ++? )
struct
ou class
n'ait aucune incidence sur le fait que votre objet soit POD ou si vous devez définir un constructeur / destructeur de copie. Les fonctions membres n'ont également aucune incidence sur quelque chose qui est POD. En relisant ce que vous avez écrit, je vois que vous ne suggérez pas le contraire, mais la formulation actuelle prête à confusion
Il y a beaucoup d'idées fausses dans les réponses existantes.
Les deux class
et struct
déclarez une classe.
Oui, vous devrez peut-être réorganiser vos mots clés de modification d'accès dans la définition de classe, selon le mot clé que vous avez utilisé pour déclarer la classe.
Mais, au-delà de la syntaxe, la seule raison de choisir l'un plutôt que l'autre est la convention / le style / la préférence.
Certaines personnes aiment s'en tenir au struct
mot - clé pour les classes sans fonctions membres, car la définition résultante "ressemble" à une structure simple de C.
De même, certaines personnes aiment utiliser le class
mot - clé pour les classes avec des fonctions membres et des private
données, car il dit "classe" dessus et ressemble donc à des exemples de leur livre préféré sur la programmation orientée objet.
La réalité est que cela dépend entièrement de vous et de votre équipe, et cela ne fera littéralement aucune différence pour votre programme.
Les deux classes suivantes sont absolument équivalentes à tous égards, sauf leur nom:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
Vous pouvez même changer de mot clé lors de la redéclaration:
class Foo;
struct Bar;
(bien que cela casse les versions de Visual Studio en raison de la non-conformité, de sorte que le compilateur émettra un avertissement lorsque vous effectuez cette opération.)
et les expressions suivantes ont toutes les deux la valeur true:
std::is_class<Foo>::value
std::is_class<Bar>::value
Notez cependant que vous ne pouvez pas changer de mot clé lors de la redéfinition ; c'est uniquement parce que (selon la règle d'une définition) les définitions de classe en double dans les unités de traduction doivent "se composer de la même séquence de jetons" . Cela signifie que vous ne pouvez même pas échanger const int member;
avec int const member;
, et n'a rien à voir avec la sémantique de class
ou struct
.
class foo { public: ... };
et qu'une autre puisse avoir struct foo { ... };
qui devrait rester vraie selon la revendication "absolument équivalente". Il en résulte que les déclarations incomplètes struct foo;
et class foo;
sont interchangeables. Ceux-ci ne spécifient pas le corps de la classe et ne parlent donc pas de la disposition d'accès.
Foo
et Bar
sont encore équivalents / types identiques. Je me suis assuré de dire "lors de la redéclaration " et de donner un exemple. À bien y penser, je vais clarifier cela dans la réponse pour m'assurer que je n'induis pas les gens en erreur dans UB
La seule fois où j'utilise une structure au lieu d'une classe, c'est quand je déclare un foncteur juste avant de l'utiliser dans un appel de fonction et que je veux minimiser la syntaxe pour des raisons de clarté. par exemple:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
De la FAQ C ++ Lite :
Les membres et les classes de base d'une structure sont publics par défaut, tandis qu'en classe, ils sont par défaut privés. Remarque: vous devez rendre vos classes de base explicitement publiques, privées ou protégées, plutôt que de vous fier aux valeurs par défaut.
struct et class sont par ailleurs fonctionnellement équivalents.
OK, assez de cette conversation techno propre et grinçante. Sur le plan émotionnel, la plupart des développeurs font une forte distinction entre une classe et une structure. Une structure ressemble simplement à une pile ouverte de bits avec très peu d'encapsulation ou de fonctionnalité. Une classe se sent comme un membre vivant et responsable de la société avec des services intelligents, une forte barrière d'encapsulation et une interface bien définie. Puisque c'est la connotation que la plupart des gens ont déjà, vous devriez probablement utiliser le mot-clé struct si vous avez une classe qui a très peu de méthodes et a des données publiques (de telles choses existent dans des systèmes bien conçus!), Mais sinon vous devriez probablement utiliser la classe mot-clé.
Un endroit où une structure m'a été utile est lorsque j'ai un système qui reçoit des messages de format fixe (par exemple, un port série) d'un autre système. Vous pouvez convertir le flux d'octets en une structure qui définit vos champs, puis accéder facilement aux champs.
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);
}
Évidemment, c'est la même chose que vous feriez en C, mais je trouve que la surcharge d'avoir à décoder le message en classe ne vaut généralement pas la peine.
operator >>
sur une classe au lieu d'écrire la processMessage
fonction, ce qui rendrait votre C ++ plus comme C ++ approprié et moins comme C.
__packed__
structure et avoir une implémentation ifdef sensible à l'endian (vous devez inverser l'ordre sur une machine où l'endianess est opposée à celle de la source de données externe fournit). Ce n'est pas joli, mais j'ai utilisé pour emballer / déballer les registres pour les périphériques distants sur les plates-formes embarquées de manière portable.
char
type, qui sont exemptés d'aliasing. Cependant, il y a toujours un problème, bien que différent: la char*
conversion de a en un type différent, s'il n'y avait pas vraiment d'objet de ce dernier type déjà initialisé à cette adresse, est UB car elle viole les règles de durée de vie. Afaik, même si le type de destination est trivialement constructible, le simple fait d'allouer de la mémoire n'est pas suffisant pour que C ++ permette formellement de traiter cette mémoire comme ce type.
Vous pouvez utiliser "struct" en C ++ si vous écrivez une bibliothèque dont les composants internes sont C ++ mais l'API peut être appelée par du code C ou C ++. Vous créez simplement un en-tête unique qui contient des structures et des fonctions d'API globales que vous exposez au code C et C ++ comme ceci:
// 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
Ensuite, vous pouvez écrire une barre de fonctions () dans un fichier C ++ en utilisant du code C ++ et la rendre appelable à partir de C et les deux mondes peuvent partager des données via les structures déclarées. Il y a bien sûr d'autres mises en garde lors du mélange de C et C ++ mais ceci est un exemple simplifié.
Comme tout le monde le dit, la seule vraie différence est l'accès par défaut. Mais j'utilise particulièrement struct quand je ne veux aucune sorte d'encapsulation avec une simple classe de données, même si j'implémente des méthodes d'assistance. Par exemple, quand j'ai besoin de quelque chose comme ça:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
Pour répondre à ma propre question (sans vergogne), Comme déjà mentionné, les privilèges d'accès sont la seule différence entre eux en C ++.
J'ai tendance à utiliser une structure pour le stockage de données uniquement. Je lui permettrai d'obtenir quelques fonctions d'assistance si cela facilite le travail avec les données. Cependant, dès que les données nécessitent un contrôle de flux (c'est-à-dire des getters / setters qui maintiennent ou protègent un état interne) ou commencent à acquérir une fonctionnalité majeure (essentiellement plus semblable à un objet), elles seront `` mises à niveau '' vers une classe pour mieux communiquer l'intention.
Les structures ( POD , plus généralement) sont pratiques lorsque vous fournissez une interface compatible C avec une implémentation C ++, car elles sont portables à travers les frontières de langage et les formats de l'éditeur de liens.
Si cela ne vous préoccupe pas, je suppose que l'utilisation de la "structure" au lieu de "classe" est un bon communicateur d'intention (comme l'a dit @ZeroSignal ci-dessus). Les structures ont également une sémantique de copie plus prévisible, elles sont donc utiles pour les données que vous avez l'intention d'écrire sur un support externe ou d'envoyer sur le câble.
Les structures sont également pratiques pour diverses tâches de métaprogrammation, comme les modèles de traits qui exposent juste un tas de typedefs dépendants:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
... Mais c'est vraiment juste profiter du niveau de protection par défaut de struct qui est public ...
Pour C ++, il n'y a vraiment pas beaucoup de différence entre les structures et les classes. La principale différence fonctionnelle est que les membres d'une structure sont publics par défaut, alors qu'ils sont privés par défaut dans les classes. Sinon, en ce qui concerne la langue, ils sont équivalents.
Cela dit, j'ai tendance à utiliser des structures en C ++ comme je le fais en C #, similaire à ce que Brian a dit. Les structures sont de simples conteneurs de données, tandis que les classes sont utilisées pour les objets qui doivent agir sur les données en plus de les conserver.
Ils sont à peu près la même chose. Grâce à la magie du C ++, un struct peut contenir des fonctions, utiliser l'héritage, créé en utilisant "new" et ainsi de suite comme une classe
La seule différence fonctionnelle est qu'une classe commence par des droits d'accès privés, tandis qu'une structure commence par publique. Il s'agit de maintenir la compatibilité descendante avec C.
Dans la pratique, j'ai toujours utilisé des structures comme supports de données et des classes comme objets.
Comme d'autres l'ont souligné
Stroustrup / Sutter recommande clairement l'utilisation:
Cependant, gardez à l'esprit qu'il n'est pas judicieux de transmettre sth. comme classe ( class X;
) et définissez-la comme struct ( struct X { ... }
). Il peut fonctionner sur certains éditeurs de liens (par exemple, g ++) et peut échouer sur d'autres (par exemple, MSVC), vous vous retrouverez donc dans l'enfer des développeurs.
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
non seulement compile et s'exécute avec MSVC 2017, il produit même un avertissement clair qui a Foo
été déclaré struct
mais défini comme class
. Mais je me souviens aussi clairement qu'il a fallu une demi-journée à notre équipe pour trouver ce stupide bug. Je ne sais pas quelle version de MSVC nous avons utilisée à l'époque.
class
ou struct
sur une déclaration directe, et les deux sont librement interchangeables selon la norme (bien que l'on sache que VS avertit; j'ai toujours supposé que c'était juste pour éviter les erreurs de programmation apparentes). Quelque chose ne sent pas ici. Êtes-vous sûr que ce n'était pas un bogue de violation ODR?
struct
-forwards en class
-forwards, les problèmes ont disparu. À ce jour, je trouve cela étrange aussi. Je serais ravi si vous pouviez nous éclairer.
Les membres de la classe sont privés par défaut.
class test_one {
int main_one();
};
Est équivalent à
class test_one {
private:
int main_one();
};
Donc, si vous essayez
int two = one.main_one();
Nous obtiendrons une erreur: main_one is private
car ce n'est pas accessible. On peut le résoudre en l'initialisant en spécifiant son public c'est à dire
class test_one {
public:
int main_one();
};
Une structure est une classe dont les membres sont publics par défaut.
struct test_one {
int main_one;
};
Les moyens main_one
sont privés c'est-à-dire
class test_one {
public:
int main_one;
};
J'utilise des structures pour les structures de données où les membres peuvent prendre n'importe quelle valeur, c'est plus facile de cette façon.
Un avantage de struct
over class
est qu'il enregistre une ligne de code, s'il adhère aux "premiers membres publics, puis privés". Dans cette optique, je trouve le mot-clé class
inutile.
Voici une autre raison d'utiliser uniquement struct
et jamais class
. Certaines directives de style de code pour C ++ suggèrent d'utiliser des minuscules pour les macros de fonction, la raison étant que lorsque la macro est convertie en fonction en ligne, le nom ne devrait pas avoir besoin d'être changé. Pareil ici. Vous avez votre belle structure de style C et un jour, vous découvrez que vous devez ajouter un constructeur ou une méthode pratique. Le changez-vous en un class
? Partout?
Faire la distinction entre struct
s et class
es est tout simplement trop compliqué, ce qui nous empêche de faire ce que nous devrions faire - la programmation. Comme tant de problèmes de C ++, il découle du fort désir de compatibilité ascendante.
class
? Pensiez-vous qu'une classe définie avec le struct
mot - clé ne peut pas avoir de fonctions membres ou un constructeur?
joe()
doit être définie avec un class
mot-clé? Chaque classe avec au moins 4 int
membres doit être définie avec un struct
mot-clé?
struct
, les agrégats avec les méthodes sont définis avec class
". Trop de tracas.
ils sont la même chose avec des valeurs par défaut différentes (privé par défaut pour class
et public par défaut pour struct
), donc en théorie ils sont totalement interchangeables.
Donc, si je veux juste empaqueter des informations pour me déplacer, j'utilise une structure, même si j'y mets quelques méthodes (mais pas beaucoup). Si c'est une chose principalement opaque, où l'utilisation principale se ferait via des méthodes, et non directement aux membres des données, j'utilise une classe complète.
Les structures par défaut ont un accès public et les classes par défaut ont un accès privé.
Personnellement, j'utilise des structures pour les objets de transfert de données ou comme objets de valeur. Lorsqu'il est utilisé comme tel, je déclare tous les membres const pour empêcher toute modification par un autre code.
Les deux struct
et class
sont les mêmes sous le capot mais avec différents paramètres par défaut quant à la visibilité, par struct
défaut est public et class
privé par défaut. Vous pouvez changer l'un ou l'autre pour être l'autre avec l'utilisation appropriée de private
et public
. Ils permettent tous les deux l'héritage, les méthodes, les constructeurs, les destructeurs et tous les autres avantages d'un langage orienté objet.
Cependant, une énorme différence entre les deux est qu'un struct
mot clé est pris en charge en C alors qu'il class
ne l'est pas. Cela signifie que l'on peut utiliser un struct
dans un fichier include qui peut être #include
en C ++ ou C tant que le struct
style est un C simple struct
et que tout le reste du fichier include est compatible avec C, c'est-à-dire pas de mots clés spécifiques C ++ tels que private
,public
, pas méthodes, pas d'héritage, etc. etc. etc.
Le style AC struct
peut être utilisé avec d'autres interfaces qui prennent en charge l'utilisation du style C struct
pour transporter des données d'avant en arrière sur l'interface.
Le style AC struct
est une sorte de modèle (pas un modèle C ++ mais plutôt un modèle ou un gabarit) qui décrit la disposition d'une zone mémoire. Au fil des ans d' interfaces utilisables à partir de C et avec les plug-ins C (ici vous regarde Java et Python et Visual Basic) ont été créés dont certains travaux avec le style C struct
.
Techniquement, les deux sont les mêmes en C ++ - par exemple, il est possible pour une structure d'avoir des opérateurs surchargés, etc.
Cependant :
J'utilise des structures lorsque je souhaite transmettre simultanément des informations de plusieurs types. J'utilise des classes lorsque j'ai affaire à un objet "fonctionnel".
J'espère que cela aide.
#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;
};
Par exemple, je retourne un étudiant struct dans les méthodes get ... () ici - profitez-en.
Quand choisiriez-vous d'utiliser la structure et quand utiliser la classe en C ++?
J'utilise struct
quand je définis functors
et POD
. Sinon j'utilise 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<>
n'est pas seulement obsolète, c ++ 17 le supprime même.
Tous les membres de la classe sont privés par défaut et tous les membres de la structure sont publics par défaut. La classe a des bases privées par défaut et Struct a des bases publiques par défaut. La structure dans le cas de C ne peut pas avoir de fonctions membres alors que dans le cas de C ++, nous pouvons ajouter des fonctions membres à la structure. À part ces différences, je ne trouve rien de surprenant à leur sujet.
J'utilise struct uniquement lorsque j'ai besoin de conserver certaines données sans aucune fonction membre associée (pour opérer sur les données membres) et accéder directement aux variables de données.
Par exemple: lecture / écriture de données à partir de fichiers et de flux de socket, etc. Passage d'arguments de fonction dans une structure où les arguments de fonction sont trop nombreux et la syntaxe de fonction semble trop longue.
Techniquement, il n'y a pas de grande différence entre la classe et la structure, sauf l'accessibilité par défaut. De plus, cela dépend du style de programmation utilisé.
Je pensais que Structs était conçu comme une structure de données (comme un tableau d'informations de type multi-données) et que les classes étaient destinées à l'empaquetage de code (comme les collections de sous-programmes et de fonctions).
:(
Je n'utilise jamais "struct" en C ++.
Je ne peux jamais imaginer un scénario où vous utiliseriez une structure quand vous voulez des membres privés, à moins que vous n'essayiez délibérément d'être déroutant.
Il semble que l'utilisation de structures soit davantage une indication syntaxique de la façon dont les données seront utilisées, mais je préfère simplement créer une classe et essayer de rendre cela explicite dans le nom de la classe ou à travers des commentaires.
Par exemple
class PublicInputData {
//data members
};
struct
déjà ne serait pas assez explicite que les membres de la classe seront, par défaut, publics?