Membres d'instance vs membres statiques
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 27 sur 104.
Jusqu'à présent, chaque variable membre que vous avez créée appartient à un objet spécifique. Lorsque vous créez deux objets Player, chacun possède ses propres name et health. Ceux-ci sont appelés des membres d'instance - ils existent séparément pour chaque instance de la classe.
Mais que se passe-t-il si vous avez besoin de données partagées entre tous les objets ? Par exemple, pour suivre le nombre total de joueurs existants.
C'est là qu'interviennent les membres statiques. Un membre statique appartient à la classe elle-même, et non à un objet particulier.
class Player {
std::string name; // Membre d'instance - chaque joueur a le sien
int health; // Membre d'instance
static int playerCount; // Membre statique - partagé par TOUS les joueurs
public:
Player(std::string n) : name(n), health(100) {
playerCount++; // Incrémenter quand un joueur est créé
}
~Player() {
playerCount--; // Décrémenter quand un joueur est détruit
}
};La différence clé : les membres d'instance sont accessibles via un objet, tandis que les membres statiques peuvent être accédés via le nom de la classe lui-même. Considérez les membres d'instance comme étant « un par objet » et les membres statiques comme étant « un par classe ».
| Membres d'instance | Membres statiques |
|---|---|
| Unique à chaque objet | Partagé par tous les objets |
| Créé lors de la création de l'objet | Existe avant qu'un objet ne soit créé |
Accédé via l'objet : player.health | Accédé via la classe : Player::playerCount |
Les membres statiques sont utiles pour les compteurs, les valeurs de configuration ou toute donnée qui appartient logiquement à la classe plutôt qu'aux objets individuels.
Défi
FacileConstruisons un système d'inventaire de produits qui suit à la fois les détails des produits individuels et les statistiques globales de l'inventaire en utilisant des membres d'instance et statiques.
Vous allez créer deux fichiers pour organiser votre code :
Product.h: Définissez une classeProductqui gère les produits individuels tout en suivant les données de l'ensemble de l'inventaire. Votre classe doit avoir :- Des membres d'instance :
name(string) etprice(double) — uniques à chaque produit - Un membre statique
totalProductsqui compte combien de produits existent actuellement - Un membre statique
totalValuequi suit le prix combiné de tous les produits - Un constructeur qui prend un nom et un prix, initialise les membres d'instance et met à jour les deux compteurs statiques (incrémente le compte, ajoute le prix à la valeur totale)
- Un destructeur qui met à jour les compteurs statiques lorsqu'un produit est supprimé (décrémente le compte, soustrait le prix de la valeur totale)
- Une méthode
getInfo()qui retourne une chaîne de caractères au format :"<name>: "<name>: $<price>"lt;price>" - Une méthode statique
getInventoryStats()qui retourne une chaîne de caractères :"Products: <count>, Total Value: "Products: <count>, Total Value: $<value>"lt;value>"
- Des membres d'instance :
main.cpp: Démontrez comment les membres statiques sont partagés entre tous les objets tandis que les membres d'instance restent uniques. Lisez deux noms de produits et leurs prix à partir de l'entrée (name1, price1, name2, price2 — chacun sur une ligne séparée), puis :- Affichez les statistiques d'inventaire initiales en utilisant le nom de la classe :
Product::getInventoryStats() - Créez un bloc de portée avec des accolades et, à l'intérieur, créez un
Productavec le premier nom et le premier prix. Affichez ses informations et les statistiques d'inventaire actuelles. - Une fois le bloc terminé (premier produit détruit), affichez
"After first scope:"suivi des statistiques d'inventaire - Créez un autre
Productavec le deuxième nom et le deuxième prix. Affichez ses informations et les statistiques d'inventaire. - Créez un troisième
Productavec le nom"Bonus"et le prix5.00. Affichez les statistiques d'inventaire finales.
- Affichez les statistiques d'inventaire initiales en utilisant le nom de la classe :
N'oubliez pas de définir vos membres statiques en dehors de la classe dans le fichier d'en-tête (après la définition de la classe). Formatez les prix avec deux décimales en utilisant std::fixed et std::setprecision(2) de <iomanip>.
Incluez votre fichier d'en-tête dans main.cpp en utilisant #include "Product.h".
Aide-mémoire
Le C++ prend en charge deux types de membres de classe : les membres d'instance et les membres statiques.
Les membres d'instance sont uniques à chaque objet - chaque instance possède sa propre copie :
class Player {
std::string name; // Chaque joueur a son propre nom
int health; // Chaque joueur a sa propre santé
};Les membres statiques sont partagés entre tous les objets d'une classe - il n'y a qu'une seule copie qui appartient à la classe elle-même :
class Player {
static int playerCount; // Partagé par TOUS les joueurs
public:
Player(std::string n) : name(n), health(100) {
playerCount++; // Incrémenter le compteur partagé
}
~Player() {
playerCount--; // Décrémenter lors de la destruction
}
};Différences clés :
| Membres d'instance | Membres statiques |
|---|---|
| Unique à chaque objet | Partagé entre tous les objets |
| Créé lors de la création de l'objet | Existe avant la création de tout objet |
Accédé via l'objet : player.health | Accédé via la classe : Player::playerCount |
Les méthodes statiques peuvent être appelées en utilisant le nom de la classe et ne peuvent accéder qu'aux membres statiques :
class Player {
static int playerCount;
public:
static int getPlayerCount() {
return playerCount; // Ne peut accéder qu'aux membres statiques
}
};
// Appel en utilisant le nom de la classe
int count = Player::getPlayerCount();Les membres statiques doivent être définis à l'extérieur de la classe (généralement dans un fichier .cpp ou après la définition de la classe dans un en-tête) :
int Player::playerCount = 0;Les membres statiques sont utiles pour les compteurs, les valeurs de configuration partagées ou toute donnée qui appartient logiquement à la classe plutôt qu'aux objets individuels.
Essayez vous-même
#include <iostream>
#include <string>
#include "Product.h"
using namespace std;
int main() {
// Lire l'entrée
string name1;
double price1;
string name2;
double price2;
getline(cin, name1);
cin >> price1;
cin.ignore();
getline(cin, name2);
cin >> price2;
// TODO: Afficher les statistiques initiales de l'inventaire en utilisant Product::getInventoryStats()
// TODO: Créer un bloc de portée avec des accolades
// À l'intérieur du bloc :
// - Créer un Product avec name1 et price1
// - Afficher ses informations en utilisant getInfo()
// - Afficher les statistiques actuelles de l'inventaire
// TODO: Une fois le bloc terminé, afficher "After first scope:"
// Ensuite, afficher les statistiques de l'inventaire
// TODO: Créer un autre Product avec name2 et price2
// Afficher ses informations et les statistiques de l'inventaire
// TODO: Créer un troisième Product avec le nom "Bonus" et le prix 5.00
// Afficher les statistiques finales de l'inventaire
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