Aller au contenu

Programmation C++/Les espaces de noms

Un livre de Wikilivres.

Les espaces de nom ont été introduits pour permettre de faire des regroupements logiques et résoudre les collisions de noms. Un espace de nom permet de regrouper plusieurs déclarations de variables, fonctions et classes dans un groupe nommé. Une pratique courante du langage C consistant à concaténer des noms entre eux afin de minimiser la probabilité de collisions avec des noms d'autres bibliothèques n'a plus raison d'être en C++. En effet, un même nom pourra être déclaré dans des espaces de noms différents évitant ainsi la collision lorsqu'ils sont inclus en même temps dans une unité.

La déclaration d'un espace de noms se fait à l'aide du mot clé namespace.

Tout comme l'accès à un membre d'une classe, l'opérateur de portée :: permet l'accès à l'ensemble des noms importés d'un espace de noms.

Avant l'introduction des espaces de noms, une pratique du C++ consistait à utiliser des classes pour faire des espaces de noms. Le problème est qu'une classe est instanciable et que sa portée est fermée. À contrario, la portée d'un espace de noms est ouvert, c'est-à-dire qu'il est possible de répartir un espace de noms sur plusieurs unités. Un espace de noms est donc extensible.

Enfin, il est possible d'imbriquer un espace de noms dans un autre espace de noms.

Un exemple d'espace de nom est std, défini par la bibliothèque standard, regroupant en autre les flux standards cin, cout et cerr. Ainsi lorsque <iostream> est inclus dans une source, il sera possible de les accéder en les dénommant par leurs noms complets std::cin, std::cout et std::cerr.

Pour simplifier le code, et les désigner sans spécifier l'espace de noms, il faut utiliser l'instruction suivante :

using namespace std;

Utiliser différents espaces de noms permet, lors d'un projet en équipe ou de l'utilisation de bibliothèque externes, de créer plusieurs entités portant le même nom.

Créer un espace de noms

[modifier | modifier le wikicode]

Pour déclarer vos fonctions, variables et classes dans votre espace de noms, placez-les dans un bloc de ce type :

namespace identifiant
{
    // Déclarations ici ...
}

Exemple :

namespace exemple
{
    int suivant(int n) {
        return n+1;
    }
}

Utiliser un espace de noms

[modifier | modifier le wikicode]

Pour utiliser les entités d'un espace de noms en dehors de celui-ci (voire dans un autre espace de noms), vous pouvez utiliser le nom précédé de l'espace de nom :

int a = exemple::suivant(5);

ou utiliser la déclaration using :

using exemple::suivant;
...
int a = suivant(5);

ou encore utiliser la directive using

using namespace exemple;
...
int a = suivant(5);

Recommandation: Il est préférable de ne pas utiliser les directives using dans un fichier entête, excepté dans les fonctions inline. En effet, la directive ayant pour effet d'ouvrir l'espace de noms à l'espace global, toute unité qui inclurait ce fichier entête se verrait automatiquement ouvrir l'espace en question pouvant provoquer rapidement des collisions si cette même unité incluait d'autres fichiers entêtes utilisant aussi la directive using sur d'autres espaces de noms.

Alias d'espace de noms

[modifier | modifier le wikicode]

Une autre manière très pratique d'utiliser un espace de noms surtout lorsque celui-ci est imbriqué dans d'autres espaces de noms sur plusieurs niveaux est l'emploi d'alias. Un alias permet de ramener une portée à un seul nom.

Exemple:

namespace global {
namespace exemple { 
   int suivant(int n);
} // namespace exemple
} // namespace global
...
namespace ge = global::exemple;  // alias
int a = ge::suivant(5);

En plusieurs fois

[modifier | modifier le wikicode]

Vous pouvez ajouter des déclarations à un espace de noms existant, par exemple lorsque vous utilisez un fichier d'en-tête et un fichier d'implémentation :

  • Fichier exemple.h
namespace exemple
{
    int suivant(int n);
}
  • Fichier exemple.cpp
#include "exemple.h"

namespace exemple
{
    int suivant(int n) {
        return n+1;
    }
}