Programmation C-C++/C++ : La couche objet/Données et fonctions membres statiques

Un livre de Wikilivres.
Cours de C/C++
^
C++ : La couche objet
Généralités
Extension de la notion de type du C
Déclaration de classes en C++
Encapsulation des données
Héritage
Classes virtuelles
Fonctions et classes amies
Constructeurs et destructeurs
Pointeur this
Données et fonctions membres statiques
Surcharge des opérateurs
Des entrées - sorties simplifiées
Méthodes virtuelles
Dérivation
Méthodes virtuelles pures - Classes abstraites
Pointeurs sur les membres d'une classe

Livre original de C. Casteyde

Nous allons voir dans ce paragraphe l'emploi du mot clé static dans les classes. Ce mot clé intervient pour caractériser les données membres statiques des classes, les fonctions membres statiques des classes, et les données statiques des fonctions membres.

Données membres statiques[modifier | modifier le wikicode]

Une classe peut contenir des données membres statiques. Ces données sont soit des données membres propres à la classe, soit des données locales statiques des fonctions membres de la classe. Dans tous les cas, elles appartiennent à la classe, et non pas aux objets de cette classe. Elles sont donc communes à tous ces objets.

Il est impossible d'initialiser les données d'une classe dans le constructeur de la classe, car le constructeur n'initialise que les données des nouveaux objets. Les données statiques ne sont pas spécifiques à un objet particulier et ne peuvent donc pas être initialisées dans le constructeur. En fait, leur initialisation doit se faire lors de leur définition, en dehors de la déclaration de la classe. Pour préciser la classe à laquelle les données ainsi définies appartiennent, on devra utiliser l'opérateur de résolution de portée (::).

Exemple 8-13. Donnée membre statique[modifier | modifier le wikicode]

class test
{
    static int i;       // Déclaration dans la classe.
    ...
};

int test::i=3;         // Initialisation en dehors de la classe.

La variable test::i sera partagée par tous les objets de classe test, et sa valeur initiale est 3.

 La définition des données membres statiques suit les mêmes règles que la définition des variables globales. Autrement dit, elles se comportent comme des variables déclarées externes. Elles sont donc accessibles dans tous les fichiers du programme (pourvu, bien entendu, qu'elles soient déclarées en zone publique dans la classe). De même, elles ne doivent être définies qu'une seule fois dans tout le programme. Il ne faut donc pas les définir dans un fichier d'en-tête qui peut être inclus plusieurs fois dans des fichiers sources, même si l'on protège ce fichier d'en-tête contre les inclusions multiples.

Les variables statiques des fonctions membres doivent être initialisées à l'intérieur des fonctions membres. Elles appartiennent également à la classe, et non pas aux objets. De plus, leur portée est réduite à celle du bloc dans lequel elles ont été déclarées. Ainsi, le code suivant :

#include <stdio.h>

class test
{
public:
    int n(void);
};

int test::n(void)
{
    static int compte=0;
    return compte++;
}

int main(void)
{
    test objet1, objet2;
    printf("%d ", objet1.n());   // Affiche 0
    printf("%d\n", objet2.n());  // Affiche 1
    return 0;
}

affichera 0 et 1, parce que la variable statique compte est la même pour les deux objets.

Fonctions membres statiques[modifier | modifier le wikicode]

Les classes peuvent également contenir des fonctions membres statiques. Cela peut surprendre à première vue, puisque les fonctions membres appartiennent déjà à la classe, c'est-à-dire à tous les objets. En fait, cela signifie que ces fonctions membres ne recevront pas le pointeur sur l'objet this, comme c'est le cas pour les autres fonctions membres. Par conséquent, elles ne pourront accéder qu'aux données statiques de l'objet.

Exemple 8-14. Fonction membre statique[modifier | modifier le wikicode]

class Entier
{
    int i;
    static int j;
public:
    static int get_value(void);
};

int Entier::j=0;

int Entier::get_value(void)
{
    j=1;         // Légal.
    return i;    // ERREUR ! get_value ne peut pas accéder à i.
}

La fonction get_value de l'exemple ci-dessus ne peut pas accéder à la donnée membre non statique i, parce qu'elle ne travaille sur aucun objet. Son champ d'action est uniquement la classe Entier. En revanche, elle peut modifier la variable statique j, puisque celle-ci appartient à la classe Entier et non aux objets de cette classe.

L'appel des fonctions membre statiques se fait exactement comme celui des fonctions membres non statiques, en spécifiant l'identificateur d'un des objets de la classe et le nom de la fonction membre, séparés par un point. Cependant, comme les fonctions membres ne travaillent pas sur les objets des classes mais plutôt sur les classes elles-mêmes, la présence de l'objet lors de l'appel est facultatif. On peut donc se contenter d'appeler une fonction statique en qualifiant son nom du nom de la classe à laquelle elle appartient à l'aide de l'opérateur de résolution de portée.

Exemple 8-15. Appel de fonction membre statique[modifier | modifier le wikicode]

class Entier
{
    static int i;
public:
    static int get_value(void);
};

int Entier::i=3;

int Entier::get_value(void)
{
    return i;
}

int main(void)
{
    // Appelle la fonction statique get_value :
    int resultat=Entier::get_value();
    return 0;
}

Les fonctions membres statiques sont souvent utilisées afin de regrouper un certain nombre de fonctionnalités en rapport avec leur classe. Ainsi, elles sont facilement localisable et les risques de conflits de noms entre deux fonctions membres homonymes sont réduits. Nous verrons également dans le Chapitre 11 comment éviter les conflits de noms globaux dans le cadre des espaces de nommage.