Pourquoi regrouper des données
Jusqu'ici, chaque variable existait seule : un int ici, un string là. Mais les vrais programmes manipulent des choses composées de plusieurs morceaux : un point a un x et un y, un étudiant a un nom, un âge et une moyenne. Faire circuler tout cela sous forme de variables séparées et éparpillées est source d'erreurs ; rien ne les relie, et une fonction qui a besoin des trois doit prendre les trois paramètres.
Un struct règle ce problème. Il définit un nouveau type qui regroupe des variables liées — ses membres — en une seule unité. Une fois défini, vous traitez l'ensemble comme une valeur unique que vous pouvez stocker, copier et passer à des fonctions.
Vous accédez à chaque membre avec l'opérateur point (s.name, s.age). Le point-virgule après l'accolade fermante } de la définition d'un struct est obligatoire ; l'oublier est l'une des erreurs de compilation les plus fréquentes chez les débutants en C++.
Initialiser un struct
Affecter chaque champ à la main fonctionne, mais c'est verbeux et il est facile d'oublier un membre. L'option la plus propre est l'initialisation par agrégat : listez les valeurs entre accolades, dans l'ordre où les membres ont été déclarés.
Attention au cas par défaut vide : Point p; (sans accolades) laisse x et y avec des valeurs indéterminées, car les membres de types intégrés ne sont pas mis à zéro automatiquement. Point p{}; les initialise par valeur à 0. Préférez les accolades. Vous pouvez aussi intégrer des valeurs par défaut directement dans la définition, de sorte que même Point p; démarre proprement :
Les structs comme paramètres de fonctions
Un struct est une valeur unique, donc une fonction peut prendre un seul paramètre au lieu de trois. Rappelez-vous simplement que passer un struct par valeur copie tous ses membres. Pour tout ce qui dépasse quelques ints, passez-le par référence const pour éviter la copie — la même règle que celle vue sur la page des références.
Renvoyer un struct entier depuis une fonction est la manière idiomatique de retourner plusieurs valeurs d'un coup — bien plus propre que de jongler avec plusieurs références de sortie.
Ajouter des fonctions membres et des constructeurs
Un struct ne se limite pas aux données. Il peut contenir des fonctions membres qui opèrent sur ses propres membres, et un constructeur qui initialise l'objet au moment de sa création. C'est là qu'un struct commence à ressembler à un petit objet doté d'un comportement.
À l'intérieur d'une fonction membre, on accède aux membres par leur nom (width, height) : ils désignent la copie de cet objet. Marquer area() const indique au compilateur que la fonction se contente de lire l'objet, ce qui vous permet de l'appeler aussi sur des valeurs const Rectangle. Les constructeurs sont un sujet à part entière, y compris cette syntaxe de liste d'initialisation : width(w) — la page des constructeurs approfondit la question.
Struct vs. class : la vraie différence
Vous avez peut-être entendu que « les structs sont pour les données, les classes pour les objets ». C'est une convention, pas une règle du langage. En C++, un struct et une class sont presque la même chose — la seule différence intégrée est le niveau d'accès par défaut.
struct S {
int x; // public par défaut
};
class C {
int x; // private par défaut
};
Les membres d'un struct sont public sauf si vous en décidez autrement ; ceux d'une class commencent en private. C'est tout — les deux peuvent avoir des constructeurs, des fonctions membres, de l'héritage et tout le reste. Vous pouvez même ajouter des spécificateurs d'accès explicites à un struct pour masquer des membres :
À retenir en pratique : utilisez struct pour des regroupements transparents de données où chaque champ est destiné à être manipulé librement (un Point, une Color, un enregistrement de configuration), et tournez-vous vers class quand vous voulez protéger l'état interne derrière une interface publique. Le compilateur les traite de la même façon ; le mot-clé ne fait que signaler votre intention.
Tableaux et vectors de structs
Comme un struct est un type ordinaire, vous pouvez en placer plusieurs dans un tableau ou un vector et les parcourir comme n'importe quelle autre valeur.
Notez les accolades imbriquées : chaque {"Keyboard", 49.99} initialise par agrégat un Product, et les accolades extérieures construisent le vector. Utiliser const Product& dans la boucle for-range évite de copier chaque struct à chaque itération — supprimez le & et vous dupliqueriez chaque élément inutilement.
Suite : les Enums
Les structs vous permettent de construire un type à partir de plusieurs valeurs regroupées. Le chapitre suivant prend la direction inverse : un enum définit un type qui peut contenir exactement une valeur parmi un petit ensemble nommé — parfait pour des choses comme Color::Red, Direction::North ou l'état d'une machine à états. Vous verrez comment enum class vous offre des constantes lisibles et sûres au niveau du type, qui se marient naturellement avec les structs et les classes que vous construisez maintenant.
Questions fréquentes
Qu'est-ce qu'un struct en C++ ?
Un struct est un type défini par l'utilisateur qui regroupe plusieurs variables liées (appelées membres) sous un même nom. Au lieu de jongler avec des variables séparées string name, int age et double gpa, vous les rassemblez dans un seul type Student et vous faites circuler cet objet unique. Un struct peut aussi contenir des fonctions membres et des constructeurs : en C++ moderne, c'est une classe à part entière dont les membres sont public par défaut.
Quelle est la différence entre struct et class en C++ ?
Techniquement, uniquement le niveau d'accès par défaut : les membres d'un struct sont public sauf indication contraire, tandis que ceux d'une class sont private par défaut. Il en va de même pour l'héritage. Tout le reste (constructeurs, fonctions membres, méthodes, héritage) fonctionne de façon identique. Par convention, les programmeurs choisissent struct pour de simples regroupements de données et class pour des types avec des invariants et des détails internes cachés.
Comment initialiser un struct en C++ ?
Le plus simple est l'initialisation par agrégat avec des accolades, dans l'ordre des membres : Point p{3, 4};. Vous pouvez aussi affecter chaque champ à la main avec l'opérateur point (p.x = 3;), donner des valeurs par défaut aux membres dans la définition (int x = 0;), ou écrire un constructeur pour que le struct se configure lui-même. L'initialisation par accolades est préférable car elle ne laisse pas silencieusement de champs non initialisés.