Programmation C-C++/Les espaces de nommage/Définition des espaces de nommage

Un livre de Wikilivres.
Cours de C/C++
^
C++ : Les espaces de nommage
Définition des espaces de nommage
Déclaration using
Directive using

Livre original de C. Casteyde

Espaces de nommage nommées[modifier | modifier le wikicode]

Lorsque le programmeur donne un nom à un espace de nommage, celui-ci est appelé un espace de nommage nommé. La syntaxe de ce type d'espace de nommage est la suivante :

namespace nom
{
    déclarations | définitions
}

nom est le nom de l'espace de nommage, et déclarations et définitions sont les déclarations et les définitions des identificateurs qui lui appartiennent.

Contrairement aux régions déclaratives classiques du langage (comme par exemple les classes), un namespace peut être découpé en plusieurs morceaux. Le premier morceaux sert de déclaration, et les suivants d'extensions. La syntaxe pour une extension d'espace de nommage est exactement la même que celle de la partie de déclaration.

Exemple 11-1. Extension de namespace[modifier | modifier le wikicode]

namespace A   // Déclaration de l'espace de nommage A.
{
   int i;
}

namespace B   // Déclaration de l'espace de nommage B.
{
    int i;
}

namespace A   // Extension de l'espace de nommage A.
{
    int j;
}

Les identificateurs déclarés ou définis à l'intérieur d'un même espace de nommage ne doivent pas entrer en conflit. Ils peuvent avoir les mêmes noms, mais seulement dans le cadre de la surcharge. Un espace de nommage se comporte donc exactement comme les zones de déclaration des classes et de la portée globale.

L'accès aux identificateurs des espaces de nommage se fait par défaut grâce à l'opérateur de résolution de portée (::), et en qualifiant le nom de l'identificateur à utiliser du nom de son espace de nommage. Cependant, cette qualification est inutile à l'intérieur de l'espace de nommage lui-même, exactement comme pour les membres des classes à l'intérieur de leur classe.

Exemple 11-2. Accès aux membres d'un namespace[modifier | modifier le wikicode]

int i=1;    // i est global.

namespace A
{
    int i=2; // i de l'espace de nommage A.
    int j=i; // Utilise A::i.
}

int main(void)
{
    i=1;     // Utilise ::i.
    A::i=3;  // Utilise A::i.
    return 0;
}

Les fonctions membres d'un espace de nommage peuvent être définies à l'intérieur de cet espace, exactement comme les fonctions membres de classes. Elles peuvent également être définies en dehors de cet espace, si l'on utilise l'opérateur de résolution de portée. Les fonctions ainsi définies doivent apparaître après leur déclaration dans l'espace de nommage.

Exemple 11-3. Définition externe d'une fonction de namespace[modifier | modifier le wikicode]

namespace A
{
    int f(void);   // Déclaration de A::f.
}

int A::f(void)     // Définition de A::f.
{
    return 0;
}

Il est possible de définir un espace de nommage à l'intérieur d'un autre espace de nommage. Cependant, cette déclaration doit obligatoirement avoir lieu au niveau déclaratif le plus externe de l'espace de nommage qui contient le sous-espace de nommage. On ne peut donc pas déclarer d'espaces de nommage à l'intérieur d'une fonction ou à l'intérieur d'une classe.

Exemple 11-4. Définition de namespace dans un namespace[modifier | modifier le wikicode]

namespace Conteneur
{
    int i;              // Conteneur::i.
    namespace Contenu
    {
        int j;          // Conteneur::Contenu::j.
    }
}

Espaces de nommage anonymes[modifier | modifier le wikicode]

Lorsque, lors de la déclaration d'un espace de nommage, aucun nom n'est donné, un espace de nommage anonyme est créé. Ce type d'espace de nommage permet d'assurer l'unicité du nom de l'espace de nommage ainsi déclaré. Les espaces de nommage anonymes peuvent donc remplacer efficacement le mot clé static pour rendre unique des identificateurs dans un fichier. Cependant, elles sont plus puissantes, parce que l'on peut également déclarer des espaces de nommage anonymes à l'intérieur d'autres espaces de nommage.

Exemple 11-5. Définition de namespace anonyme[modifier | modifier le wikicode]

namespace
{
    int i;         // Équivalent à unique::i;
}

Dans l'exemple précédent, la déclaration de i se fait dans un espace de nommage dont le nom est choisi par le compilateur de manière unique. Cependant, comme on ne connaît pas ce nom, le compilateur utilise une directive using (voir plus loin) afin de pouvoir utiliser les identificateurs de cet espace de nommage anonyme sans préciser leur nom complet avec l'opérateur de résolution de portée.

Si, dans un espace de nommage, un identificateur est déclaré avec le même nom qu'un autre identificateur déclaré dans un espace de nommage plus global, l'identificateur global est masqué. De plus, l'identificateur ainsi défini ne peut être accédé en dehors de son espace de nommage que par un nom complètement qualifié à l'aide de l'opérateur de résolution de portée. Toutefois, si l'espace de nommage dans lequel il est défini est un espace de nommage anonyme, cet identificateur ne pourra pas être référencé, puisqu'on ne peut pas préciser le nom des espaces de nommage anonymes.

Exemple 11-6. Ambiguïtés entre namespaces[modifier | modifier le wikicode]

namespace
{
    int i;          // Déclare unique::i.
}

void f(void)
{
    ++i;            // Utilise unique::i.
}

namespace A
{
    namespace
    {
        int i;     // Définit A::unique::i.
        int j;     // Définit A::unique::j.
    }

    void g(void)
    {
        ++i;       // Erreur : ambiguïté entre unique::i
                   // et A::unique::i.
        ++A::i;    // Erreur : A::i n'est pas défini
                   // (seul A::unique::i l'est).
        ++j;       // Correct : ++A::unique::j.
    }
}

Alias d'espaces de nommage[modifier | modifier le wikicode]

Lorsqu'un espace de nommage porte un nom très compliqué, il peut être avantageux de définir un alias pour ce nom. L'alias aura alors un nom plus simple.

Cette opération peut être réalisée à l'aide de la syntaxe suivante :

namespace nom_alias = nom;

nom_alias est ici le nom de l'alias de l'espace de nommage, et nom est le nom de l'espace de nommage lui-même.

Les noms donnés aux alias d'espaces de nommage ne doivent pas entrer en conflit avec les noms des autres identificateurs du même espace de nommage, que celui-ci soit l'espace de nommage de portée globale ou non.