Concept du mot-clé static
En C++, le mot-clé static est appliqué aux membres d'une classe pour les rendre partagés entre toutes les instances. Une variable statique appartient à la classe elle-même plutôt qu'à un objet spécifique, et une fonction statique peut être appelée sans instance d'objet. Les variables statiques doivent être initialisées en dehors de la définition de la classe.
Motivation pour l'utilisation de static
Dans les fonctions standard, les variables locales sont allouées sur la pile et détruites à la fin de l'exécution. Pour conserver une valeur entre les appels de fonction, une solution courante consiste à utiliser une variable globale, mais cela peut compromettre la portée et la sécurité. Le mot-clé static offre une alternative plus contrôlée. De plus, en C++, lorsqu'une donnée doit être partagée entre tous les objets d'une classe sans briser l'encapsulation, la déclaration statique est appropriée.
Considérons un exemple pratique : compter le nombre d'objets créés pour une classe donnée. Une approche initiale pourrait utiliser une variable globale, comme illustré ci-dessous.
#include <iostream>
int totalObjets = 0;
class Exemple1 {
public:
Exemple1() { totalObjets++; }
Exemple1(const Exemple1& autre) { totalObjets++; }
};
void traite(Exemple1 obj) {
totalObjets++;
}
int main() {
Exemple1 a;
Exemple1 b(a);
traite(a);
std::cout << totalObjets << std::endl;
return 0;
}
Cette méthode manque de sécurité, car la variable globale est accessible partout et modifiable sans restriction, ce qui viole les principes de la programmation orientée objet.
Implémentation avec des membres statiques
Pour résoudre ces problèmes, nous pouvons déclarer un compteur comme membre statique de la classe, comme suit.
#include <iostream>
class Exemple2 {
public:
Exemple2() { nbInstances++; }
Exemple2(const Exemple2& autre) { nbInstances++; }
static int obtenirNb() { return nbInstances; }
private:
static int nbInstances;
};
int Exemple2::nbInstances = 0; // Initialisation hors de la classe
int main() {
Exemple2 x;
Exemple2 y(x);
std::cout << "Nombre d'instances : " << Exemple2::obtenirNb() << std::endl;
return 0;
}
Dans cette implémentation, la variable statique nbInstances est partagée par tous les objets de la classe Exemple2. L'initialisation doit être effectuée séparément en dehors de la classe, avec le qualificateur de classe pour spécifier la portée.
Les caractéristiques clés des membres statiques incluent :
- Ils sont stockés dans la zone mémoire statique (section de données) et partagés entre toutes les instances de la classe.
- Les variables statiques ne peuvent pas être initialisées dans la liste d'initialisation du constructeur ; elles nécessitent une définition externe.
- Les fonctions statiques n'ont pas de pointeur
thisimplicite et ne peuvent accéder qu'à des membres statiques directement.
Relations d'accès entre membres statiques et non statiques
Une fonction membre statique peut appeler d'autres fonctions statiques ou accéder à des variables statiques, mais elle ne peut pas interagir avec des membres non statiques, car ces derniers nécessitent un pointeur this lié à une instance spécifique. Inversement, les fonctions non statiques peuvent appeler des fonctions statiques en utilisant le nom de la classe ou une instance.
Aspects avancés et considérations
Les variables statiques globales et locales se comportent différemment en termes de portée et de durée de vie. Une variable statique locale dans une fonction conserve sa valeur entre les appels tout en restant limitée à cette fonction. Les fonctions statiques déclarées avec le mot-clé static sont limitées à leur fichier source, améliorant ainsi la modularité du code. En contexte de classe, les membres statiques facilitent le partage de données sans compromettre l'encapsulation, offrant un équilibre entre accessibilité et contrôle.