Listes d'initialisation du constructeur
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 22 sur 104.
Vous avez vu la syntaxe avec deux-points dans les leçons précédentes comme Player(std::string n, int h) : name(n), health(h) {}. Ceci est appelé une liste d'initialisation de membres, et c'est la méthode préférée pour initialiser les membres en C++.
La liste d'initialisation apparaît après la liste des paramètres du constructeur, commençant par deux-points. Chaque membre est initialisé directement avec sa valeur, séparés par des virgules :
class Rectangle {
int width;
int height;
const int id;
int& reference;
public:
Rectangle(int w, int h, int i, int& r)
: width(w), height(h), id(i), reference(r) {
// Corps du constructeur (peut être vide)
}
};Pourquoi utiliser des listes d'initialisation au lieu de l'affectation dans le corps du constructeur ? Avec l'affectation, les membres sont d'abord construits par défaut, puis se voient affecter de nouvelles valeurs. Avec les listes d'initialisation, les membres sont construits directement avec les bonnes valeurs - ce qui est plus efficace et parfois obligatoire.
Certains membres doivent être initialisés en utilisant la liste :
- membres
const- ne peuvent pas être assignés après la construction
- Membres de type référence - doivent être liés lors de l'initialisation
- Membres sans constructeurs par défaut
class Player {
const int maxHealth; // Doit utiliser une liste d'initialisation
std::string name;
public:
// Ceci fonctionne
Player(int max, std::string n) : maxHealth(max), name(n) {}
// Ceci ne compilerait PAS :
// Player(int max) { maxHealth = max; } // Erreur !
};Les membres sont initialisés dans l'ordre dans lequel ils sont déclarés dans la classe, et non dans l'ordre de la liste d'initialisation. Écrivez toujours votre liste d'initialisation dans l'ordre de déclaration pour éviter toute confusion.
Défi
FacileConstruisons un système de configuration pour un moteur de jeu qui démontre quand et pourquoi les listes d'initialisation des membres sont essentielles. Vous allez créer une classe GameConfig avec des membres qui doivent être initialisés en utilisant la syntaxe de la liste d'initialisation.
Vous allez créer deux fichiers pour organiser votre code :
GameConfig.h: Définissez une classeGameConfigqui stocke les paramètres du jeu. Votre classe doit avoir :- Un
const std::string gameName— le titre du jeu, qui ne peut pas changer après la création - Un
const int maxPlayers— le nombre maximum de joueurs, fixé à la construction - Un
int& difficultyRef— une référence à un paramètre de difficulté externe - Un
int screenWidthetint screenHeight— des membres réguliers pour les paramètres d'affichage - Un constructeur qui prend tous les paramètres nécessaires et initialise chaque membre en utilisant la liste d'initialisation. La liste d'initialisation doit suivre l'ordre dans lequel les membres sont déclarés dans la classe
- Une méthode
display()qui affiche la configuration dans ce format :Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
- Un
main.cpp: Lisez les valeurs de configuration à partir de l'entrée et créez un objet GameConfig. Vous devrez :- Lire le nom du jeu (string), le nombre max de joueurs (int), la difficulté (int), la largeur (int) et la hauteur (int) depuis l'entrée — chacun sur une ligne séparée
- Créer une variable locale
intpour la difficulté que la configuration référencera - Créer un objet
GameConfigen utilisant le constructeur avec liste d'initialisation - Appeler
display()pour afficher la configuration initiale - Modifier la variable de difficulté directement (multipliez-la par 2)
- Afficher
"After difficulty change:" - Appeler
display()à nouveau pour montrer que la référence reflète la valeur mise à jour
Ce défi met en évidence pourquoi les listes d'initialisation sont importantes : vos membres const et votre membre de référence ne peuvent pas être assignés dans le corps du constructeur — ils doivent être initialisés dans la liste. Le membre de référence démontre également comment les modifications apportées à la variable d'origine sont reflétées à travers l'objet de configuration.
Incluez votre fichier d'en-tête dans main.cpp en utilisant #include "GameConfig.h".
Aide-mémoire
Une liste d'initialisation de membres est la méthode privilégiée pour initialiser les membres d'une classe en C++. Elle apparaît après la liste des paramètres du constructeur, commençant par deux-points, chaque membre étant initialisé directement :
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {
// Corps du constructeur
}
};Pourquoi utiliser des listes d'initialisation ? Les membres sont construits directement avec les valeurs correctes au lieu d'être construits par défaut puis assignés, ce qui est plus efficace.
Requis pour certains membres :
- Membres
const- ne peuvent pas être assignés après la construction - Membres de référence - doivent être liés lors de l'initialisation
- Membres sans constructeurs par défaut
class Player {
const int maxHealth;
int& reference;
public:
// Correct - utilise la liste d'initialisation
Player(int max, int& r) : maxHealth(max), reference(r) {}
// Erreur - impossible d'assigner const ou référence dans le corps
// Player(int max) { maxHealth = max; }
};Important : Les membres sont initialisés dans l'ordre où ils sont déclarés dans la classe, et non dans l'ordre de la liste d'initialisation. Écrivez toujours votre liste d'initialisation dans l'ordre de déclaration.
Essayez vous-même
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// Lire les valeurs d'entrée
string gameName;
getline(cin, gameName);
int maxPlayers;
cin >> maxPlayers;
int difficulty;
cin >> difficulty;
int width;
cin >> width;
int height;
cin >> height;
// TODO: Créer un objet GameConfig en utilisant le constructeur avec liste d'initialisation
// Le constructeur doit recevoir : gameName, maxPlayers, difficulty (par référence), width, height
// TODO: Appeler display() pour afficher la configuration initiale
// TODO: Modifier la variable difficulty directement (la multiplier par 2)
// TODO: Afficher "After difficulty change:"
// TODO: Appeler display() à nouveau pour afficher la configuration mise à jour
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesBuild et Compilation C++Fichiers d'en-tête et Fichiers sourceEspaces de noms et PortéeIntroduction à la POO en C++Classes vs ObjetsLe pointeur 'this'Méthodes (Fonctions membres)Attributs (Membres de données)Bases des Ctors et DtorsRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d'instance vs membres statiquesGetters et SettersFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d'accès à l'héritageOrdre d'appel des Ctor et DtorRedéfinition de méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif - Hiérarchie des employés10Présentation de la STL
Présentation et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - Fréquence des mots13Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonFabrique & Fabrique abstraitePatron MonteurPatron ObservateurPatron Stratégie2Gestion de la mémoire
Mémoire Pile vs TasPointeurs et RéférencesMémoire dynamique (new/delete)Smart Pointers en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d'accès en C++Spécificateurs d'accès en profondeurMasquage d'informationStruct vs ClassClasses imbriquées et internesRécapitulatif - Système de gestion d'étudiants8Polymorphisme
Polymorphisme : Compilation vs ExécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d'interfaces en C++Dynamic Casting & RTTIRécapitulatif - Calculateur de formes11Concepts avancés de la POO
Composition vs HéritageMixins via CRTPIdiome PimplEffacement de typeEnum Classes & Typage fortGestion des exceptions en POOHiérarchies d'exceptions personnalisées14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeRAII en tant que patron3Constructeurs et Destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d'initialisation du constructeurConstructeurs déléguésAnalyse approfondie du destructeurRègle de trois / cinq / zéroRécapitulatif - Classe String6Surcharge d'opérateurs
Introduction à la surcharge d'opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l'opérateur d'affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif - Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation de templatesTemplates variadiquesBases de SFINAE & Type TraitsRécapitulatif - Conteneur générique