Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Langage C++
  3. Bibliothèques, modules et espaces de noms
Extrait - Langage C++ De l'héritage C au C++ moderne (avec programmes d'illustration) (2e édition)
Extraits du livre
Langage C++ De l'héritage C au C++ moderne (avec programmes d'illustration) (2e édition) Revenir à la page d'achat du livre

Bibliothèques, modules et espaces de noms

Créer une bibliothèque classique (.h)

En C comme en C++, il est rapidement nécessaire de savoir créer sa propre bibliothèque. Une bibliothèque est à l’origine désignée par un fichier (.h) nommé « header » en anglais qui contient des définitions de types comme les structures et les classes, mais aussi des déclarations de fonction et des constantes.

Le programme « entite » réalisé au chapitre Classes dans la section De la structure à la classe - Un programme C muté objet C++ contient un certain nombre de fonctions outils. Nous allons placer ces fonctions dans un fichier "outils.cpp" à part et créer une bibliothèque "outils.h" avec les déclarations de ces fonctions. Ensuite, pour disposer de ces fonctions, il suffira d’inclure la bibliothèque dans le fichier où ces fonctions sont utilisées et d’ajouter le fichier .cpp qui contient le code des fonctions au programme. La démarche est la suivante :

Créez et ajoutez un nouveau fichier .cpp au programme. Sous Visual Studio :

 Dans l’Explorateur de solutions, sélectionnez votre projet, effectuez un clic droit.

 Dans le menu contextuel, sélectionnez Ajouter puis Nouvel élément.

 Dans la fenêtre qui s’ouvre, sélectionnez Fichier C++ (.cpp).

 En bas dans la boîte de saisie, nommez le fichier en "outils.cpp".

 Cliquez sur Ajouter.

Ce qui donne :

images/01RI14.png

Même opération pour cette fois créer un fichier d’en-tête (.h) :

 Dans l’Explorateur de solutions, sélectionnez votre projet, effectuez un clic droit.

 Dans le menu contextuel, sélectionnez Ajouter puis Nouvel...

Espaces de noms (namespace)

1. Cartographier du code

Les espaces de noms n’ont pas d’incidence sur la compilation mais ils donnent une possibilité supplémentaire d’exprimer dans le programme des regroupements logiques, des unités d’action. Le code va pouvoir être cartographié selon des secteurs d’activité de façon claire. Plus un programme sera long et plus il aura besoin de répartir ses composants entre plusieurs espaces nommés. De plus, des conflits de noms entre éléments différents portant les mêmes noms peuvent être évités s’ils appartiennent à des espaces de noms différents. Cette répartition du code peut aussi convenir à un travail d’équipe, chacun apporte alors au programme l’espace de noms qu’il a élaboré sur tel ou tel aspect.

2. Accéder au contenu

Un espace de noms contient du code et le code contenu n’est visible que dans cet espace. L’instruction namespace permet d’écrire ses propres espaces de noms. La syntaxe est la suivante :

namespace monEspace{       // le nom de l'espace de noms 
 
     // ici les déclarations et les définitions de variables, 
     // fonctions, classes, objets... 
 
} 

L’accès du dehors aux éléments de l’espace de noms se fait ensuite avec l’opérateur d’accès :: (aussi utilisé pour localiser la déclaration d’une fonction dans une classe) :

    <nomEspace>::<nom de l'élément de l'espace de noms> 

Par exemple :

/*main.cpp*/ 
#include <iostream> 
 
namespace ToutpourlesChiens 
{ ...

La directive using

1. Faciliter l’accès à un espace de noms

La directive using s’utilise souvent pour faciliter l’accès aux éléments d’un espace de noms. Elle peut cibler tous les éléments de l’espace de noms ou uniquement un élément particulier.

Par exemple, soit deux espaces de noms :

namespace E1 
{ 
    int v1; 
    void f1() {} 
}  
namespace E2 
{ 
    int v2; 
    void f2() {} 
} 
// directives using : 
using E1::v1;      // accès direct uniquement pour v1 dans E1 
using namespace E2;// accès direct pour tous les éléments de E2 
 
int main()  
{ 
    v1 = 10;     // utilise le using E1::v1 
    E1::f1();    // pas de using 
  
    v2 = 20;     // utilise le using 
    f2();        // général pour E2 
 
    return 0;  
} 

Un espace de noms anonyme a en réalité un nom caché attribué par la machine (par exemple $$$) et un using implicite est implémenté à partir de ce nom :

namespace perso 
{ 
    // espace de noms anonyme 
    namespace 
    { 
        void f(){ } 
 
    } 
    //using namespace $$$;  using implicite sur nom caché 
    void...

Modules (C++20)

1. Principe

L’utilisation de la directive #include, qui remonte au début du langage C, est très ancienne. Quoique toujours en usage et probablement encore pour longtemps, elle pose cependant indéniablement quelques problèmes. Elle alourdit la compilation lorsqu’une bibliothèque est incluse un grand nombre de fois. Mais surtout, lorsqu’il y a des interdépendances entre données de plusieurs bibliothèques, l’ordre des inclusions peut s’avérer important et constituer une source de bogues s’il n’est pas respecté. C’est pourquoi C++ tend à s’en affranchir pour l’avenir en fournissant depuis peu un nouvel outil appelé module.

Un module est constitué de code compilé une fois pour toutes dans un fichier binaire. Tous les fichiers sources qui importent le module accèdent aux types et fonctions exportés qu’il contient directement en binaire, ce qui est beaucoup plus rapide que le traitement d’un fichier d’en-tête. Chaque module étant en quelque sorte autosuffisant une fois compilé, il n’y a pas d’interdépendance entre différents modules, ce qui permet des importations dans n’importe quel ordre.

En outre, les modules peuvent être utilisés conjointement avec des fichiers d’en-tête de bibliothèques afin d’assurer compatibilité et transition progressive vers cette nouvelle technique.

Les modules nécessitent d’utiliser une version C++20 ou ultérieure du langage. Les instructions pour configurer un projet Visual Studio en C++20 sont détaillées au chapitre Premiers programmes dans la section Activer C++20.

2. Créer une unité d’interface de module (.ixx)

Un module se compose d’un ou plusieurs fichiers. Il contiendra...

Précision sur la liaison entre C++ et C

Lors de la réalisation de bibliothèques sophistiquées, l’instruction extern "C" permet de spécifier la convention d’édition des liens du langage C. Toutefois, le "C" de l’expression extern "C" ne désigne pas uniquement le langage C, mais permet de prendre en charge tous les langages qui adhèrent à cette même convention de liaison (Assembleur et Fortan notamment). "C" comme "convention de liaison" désigne un type d’édition de liens relatif au langage à intégrer afin de pouvoir le traiter si l’environnement le permet (il faut consulter la documentation du compilateur pour connaître ses possibilités).

L’expression extern "C" peut être utilisée pour une seule instruction, un bloc d’instructions, ou une librairie. Par exemple, pour intégrer du C dans du C++, nous pouvons avoir l’instruction suivante :

extern "C" char* strcpy(char*, const char*); 

Cette instruction spécifie que la fonction strcpy() de la librairie standard C devra être liée selon les conventions d’édition des liens du C.

Pour un bloc d’instructions :

extern "C"{ 
    char* strcpy(char*, const char*); 
    int strlen(const char*); 
    int strcmp(const char*, const char*); 
} 

Toutes ces instructions de la librairie standard C devront être liées selon les conventions d’édition des liens du C.

Pour une librairie :

extern "C"{ 
    #include <string.h> 
} 

La librairie entière et le code correspondant devront être liés selon les conventions d’édition des liens...