Comment utiliser correctement les namespaces en C++?

je viens d'un fond Java, où les paquets sont utilisés, pas les espaces de noms. Je suis habitué à mettre des classes qui fonctionnent ensemble pour former un objet complet en paquets, et ensuite les réutiliser plus tard à partir de ce paquet. Mais maintenant je travaille en C++.

comment utilisez-vous les namespaces en C++? Créez-vous un namespace unique pour l'ensemble de l'application, ou créez-vous des namespaces pour les principaux composants? Si oui, comment créer des objets à partir de classes dans d'autres namespaces?

223
demandé sur Philipp Matthias Schäfer 2008-09-03 16:54:06

15 réponses

Les espaces de noms

sont essentiellement des paquets. Ils peuvent être utilisés comme ceci:

namespace MyNamespace
{
  class MyClass
  {
  };
}

puis en code:

MyNamespace::MyClass* pClass = new MyNamespace::MyClass();

Espère que ça aide.

Ou, si vous voulez toujours utiliser un espace de noms spécifique, vous pouvez faire ceci:

using namespace MyNamespace;

MyClass* pClass = new MyClass();

Edit: à la Suite de ce bernhardrusch a dit, j'ai tendance à ne pas utiliser le "using namespace x" syntaxe à tous, j' habituellement spécifiez explicitement l'espace de noms lors de l'instanciation de mes objets (i.e. le premier exemple que j'ai montré).

et comme vous avez demandé ci-dessous , vous pouvez utiliser autant d'espaces de noms que vous le souhaitez.

160
répondu Mark Ingram 2017-05-23 10:31:31

pour éviter de dire tout ce que Mark Ingram a déjà dit un petit conseil pour l'utilisation des espaces de noms:

éviter la directive" using namespace " dans les fichiers d'en - tête-ceci ouvre l'Espace-nom pour toutes les parties du programme qui importent ce fichier d'en-tête. Dans les fichiers de mise en œuvre (*.cpp) ce n'est normalement pas un gros problème - bien que je préfère utiliser la directive "using namespace" au niveau de la fonction.

je pense que les namespaces sont surtout utilisés pour éviter de nommer conflits - pas nécessairement pour organiser votre structure de code. J'organiserais des programmes c++ principalement avec des fichiers d'en-tête / la structure du fichier.

il arrive que des namespaces soient utilisés dans de plus grands projets C++ pour masquer des détails d'implémentation.

Note complémentaire à la directive d'utilisation: Certaines personnes préfèrent utiliser "Utiliser" juste pour les éléments simples:

using std::cout;  
using std::endl;
112
répondu bernhardrusch 2012-03-11 15:51:48

Vincent Robert a raison dans son commentaire comment utilisez-vous correctement les namespaces en C++? .

Using namespace

Les espaces de noms

sont utilisés à tout le moins pour éviter les conflits de noms. En Java, Ceci est appliqué par l'intermédiaire de "org.domaine " idiome (parce que c'est supposé que l'on n'utilisera rien d'autre que son propre nom de domaine).

en C++, vous pouvez donner un namespace à tout le code de votre module. Pour exemple, pour un module MyModule.dll, vous pouvez donner son code le Namespace MyModule. J'ai vu ailleurs quelqu'un utiliser MyCompany::MyProject::MyModule. Je suppose que c'est exagéré, mais tout compte fait, ça me semble correct.

utilisant" utiliser "

utiliser devrait être utilisé avec grand soin parce qu'il importe effectivement un (ou tous) symboles d'un espace de noms dans votre espace de noms courant.

C'est mal de le faire dans un fichier d'en-tête, parce que votre header polluera toutes les sources y compris elle (elle me rappelle des macros...), et même dans un fichier source, le mauvais style en dehors d'une portée de fonction parce qu'il importera à la portée globale les symboles de l'espace de noms.

la manière La plus sûre d'utiliser "utiliser" est d'importer, sélectionnez les symboles:

void doSomething()
{
   using std::string ; // string is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   std::cout << a << std::endl ;
}

void doSomethingElse()
{
   using namespace std ; // everything from std is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   cout << a << endl ;
}

vous verrez beaucoup de" utilisation de namespace std; " dans le tutoriel ou les codes d'exemple. La raison est de réduire le nombre de symboles pour rendre la lecture plus facile, non parce que c'est une bonne idée.

"utiliser namespace std;" est découragé par Scott Meyers (Je ne me souviens pas exactement quel livre, mais je peux le trouver si nécessaire).

Espace De Noms De La Composition

Les espaces de noms

sont plus que des paquets. Un autre exemple peut être trouvé dans le "langage de programmation C++"de Bjarne Stroustrup.

dans l '"édition spéciale", à 8.2.8 Composition de L'Espace-nom , il décrit comment vous pouvez fusionner deux espaces de noms AAA et BBB dans un autre appelé CCC. Ainsi, CCC devient un alias pour AAA et BBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

namespace CCC
{
   using namespace AAA ;
   using namespace BBB ;
}

void doSomethingAgain()
{
   CCC::doSomething() ;
   CCC::doSomethingElse() ;
}

vous pouvez même importer des symboles select de différents espaces de noms, pour construire votre propre interface d'espace de noms personnalisée. Je dois encore trouver une utilisation pratique de cette, mais en théorie, il est cool.

76
répondu paercebal 2017-08-07 07:42:03

Je n'en ai pas vu mention dans les autres réponses, alors voici mes 2 cents canadiens:

sur le thème" utilisation de l'espace de noms", une déclaration utile est l'alias de l'espace de noms, vous permettant de" renommer " un espace de noms, normalement pour lui donner un nom plus court. Par exemple, au lieu de:

Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::TheClassName foo;
Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::AnotherClassName bar;

vous pouvez écrire:

namespace Shorter = Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally;
Shorter::TheClassName foo;
Shorter::AnotherClassName bar;
70
répondu Éric Malenfant 2009-10-21 13:19:01

n'écoutez pas tous les gens vous dire que les espaces-noms sont des espaces-noms.

Ils sont importants parce qu'ils sont considérés par le compilateur pour appliquer le principe de l'interface. Fondamentalement, il peut être expliqué par un exemple:

namespace ns {

class A
{
};

void print(A a)
{
}

}

si vous vouliez imprimer un objet A, le code serait celui-ci:

ns::A a;
print(a);

notez que nous n'avons pas explicitement mentionné l'espace de noms lors de l'appel de la fonction. C'est le principe de l'interface: c++ considère une fonction prenant un type comme argument comme faisant partie de l'interface pour ce type, donc pas besoin de spécifier l'espace de noms parce que le paramètre impliquait déjà l'espace de noms.

pourquoi ce principe est-il important? Imaginez que la classe A author n'ait pas fourni de fonction print() pour cette classe. Vous devrez fournir un vous-même. Comme vous êtes un bon programmeur, vous allez définir cette fonction dans votre propre espace de noms, ou peut-être dans le espace de noms global.

namespace ns {

class A
{
};

}

void print(A a)
{
}

et votre code peut commencer à appeler la fonction print(a) où vous voulez. Maintenant, imaginez que des années plus tard, l'auteur décide de fournir une fonction print (), meilleure que la vôtre parce qu'il connaît les internes de sa classe et peut faire une meilleure version que la vôtre.

puis C++ Les auteurs ont décidé que sa version de la fonction print () devrait être utilisée à la place de celle fournie dans un autre espace de nom, pour respecter le principe de l'interface. Et que cette" mise à jour " de la fonction print() devrait être aussi simple que possible, ce qui signifie que vous n'aurez pas à changer chaque appel à la fonction print (). C'est pourquoi les" fonctions d'interface " (fonction dans le même espace de noms qu'une classe) peuvent être appelées sans spécifier l'espace de noms en C++.

et c'est pourquoi vous devriez considérer un namespace C++ comme une" interface " lorsque vous en utilisez une et gardez à l'esprit le principe de l'interface.

si vous vous voulez une meilleure explication de ce comportement, vous pouvez vous référer au livre C++ exceptionnel de Herb Sutter

53
répondu Vincent Robert 2010-10-30 04:57:28

plus grands projets C++ j'ai vu à peine utilisé plus d'un espace de noms (par exemple boost library).

réellement boost utilise des tonnes d'espaces de noms, généralement chaque partie de boost a son propre espace de noms pour le fonctionnement interne et peut ensuite mettre seulement l'interface publique dans l'espace de noms de haut niveau boost.

personnellement je pense que plus une base de code devient grande, plus les espaces de noms importants deviennent, même à l'intérieur d'un seul application (ou bibliothèque). Au travail nous mettons chaque module de notre application dans son propre espace de nom.

une autre utilisation (sans jeu de mots) des espaces de noms que j'utilise beaucoup est l'espace de noms anonyme:

namespace {
  const int CONSTANT = 42;
}

c'est essentiellement la même chose que:

static const int CONSTANT = 42;

utilisant un espace de nom anonyme (au lieu de statique) est cependant le moyen recommandé pour que le code et les données soient visibles seulement dans l'Unité de compilation actuelle en C++.

36
répondu 2008-09-07 00:38:54

aussi, notez que vous pouvez ajouter à un espace de noms. C'est plus clair avec un exemple, ce que je veux dire, c'est que vous pouvez avoir:

namespace MyNamespace
{
    double square(double x) { return x * x; }
}

dans un fichier square.h , et

namespace MyNamespace
{
    double cube(double x) { return x * x * x; }
}

dans un fichier cube.h . Cela définit un espace de noms unique MyNamespace (c'est-à-dire que vous pouvez définir un espace de noms unique à travers plusieurs fichiers).

18
répondu OysterD 2015-07-23 21:24:09

En Java:

package somepackage;
class SomeClass {}

En C++:

namespace somenamespace {
    class SomeClass {}
}

et en Les utilisant, Java:

import somepackage;

Et C++:

using namespace somenamespace;

aussi, les noms complets sont " somepackge.SomeClass "pour Java et" somenamespace::SomeClass " pour C++. En utilisant ces conventions, vous pouvez organiser comme vous êtes habitués à le faire en Java, y compris faire correspondre les noms de dossiers pour les espaces de noms. Le dossier->le paquet et fichier->classe exigences ne sont pas là cependant, de sorte que vous pouvez nommer vos dossiers et classes indépendamment des paquets et des espaces de noms.

11
répondu Staale 2008-09-03 13:09:44

vous pouvez aussi contenir" en utilisant namespace ..."à l'intérieur d'une fonction, par exemple:

void test(const std::string& s) {
    using namespace std;
    cout << s;
}
5
répondu Shadow2531 2008-09-03 14:59:01

@ marius

Oui, vous pouvez utiliser plusieurs espaces de noms à la fois, par exemple:

using namespace boost;   
using namespace std;  

shared_ptr<int> p(new int(1));   // shared_ptr belongs to boost   
cout << "cout belongs to std::" << endl;   // cout and endl are in std

[fév. 2014 -- (ça fait si longtemps?): Cet exemple est maintenant ambigu, comme Joey le souligne ci-dessous. Boost et std:: maintenant chacun a un shared_ptr.]

5
répondu Adam Hollidge 2017-05-23 11:54:50

en général, je crée un namespace pour un corps de code si je pense qu'il pourrait y avoir des conflits de fonctions ou de noms de type avec d'autres bibliothèques. Il aide également à code de marque, ala boost:: .

3
répondu Adam Hollidge 2008-09-03 13:00:19

je préfère utiliser un namespace de haut niveau pour l'application et des sous-namespaces pour les composants.

la façon dont vous pouvez utiliser les classes d'autres espaces de noms est étonnamment très similaire à celle de java. Vous pouvez utiliser "use NAMESPACE" qui est similaire à une déclaration "import PACKAGE", Par exemple use std. Ou vous spécifiez le paquet comme préfixe de la classe séparée par"::", par exemple std:: string. Ceci est similaire à java.lang.String " en Java.

3
répondu dmeister 2008-09-03 13:00:50

notez qu'un espace de noms en C++ n'est vraiment qu'un espace de noms. Ils ne fournissent aucun des Encapsulations que les paquets font en Java, donc vous ne les utiliserez probablement pas autant.

3
répondu Kristopher Johnson 2008-09-03 13:19:09

j'ai utilisé les namespaces C++ de la même manière que je le fais en C#, Perl, etc. C'est juste une séparation sémantique des symboles entre des trucs de bibliothèque standard, des trucs de tiers, et mon propre code. Je placerais ma propre application dans un namespace, puis un composant de bibliothèque réutilisable dans un autre namespace pour la séparation.

2
répondu spoulson 2008-09-03 13:38:25

une autre différence entre java et C++, est que dans C++, la hiérarchie de l'espace de noms n'a pas besoin de mach layout du système de fichiers. J'ai donc tendance à mettre toute une bibliothèque réutilisable dans un espace de noms unique, et des sous-systèmes dans la bibliothèque dans des sous-répertoires:

#include "lib/module1.h"
#include "lib/module2.h"

lib::class1 *v = new lib::class1();

Je ne mettrais les sous-systèmes dans des espaces de noms imbriqués que s'il y avait une possibilité de conflit de noms.

2
répondu KeithB 2016-03-15 19:54:07