Question

Je viens d'un milieu Java, où les packages sont utilisés, pas les espaces de noms.J'ai l'habitude de regrouper des classes qui fonctionnent ensemble pour former un objet complet dans des packages, puis de les réutiliser plus tard à partir de ce package.Mais maintenant je travaille en C++.

Comment utiliser les espaces de noms en C++ ?Créez-vous un espace de noms unique pour l'ensemble de l'application ou créez-vous des espaces de noms pour les principaux composants ?Si oui, comment créer des objets à partir de classes dans d’autres espaces de noms ?

Était-ce utile?

La solution

Les espaces de noms sont essentiellement des packages.Ils peuvent être utilisés comme ceci :

namespace MyNamespace
{
  class MyClass
  {
  };
}

Puis en code :

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

J'espère que cela pourra aider.

Ou, si vous souhaitez toujours utiliser un espace de noms spécifique, vous pouvez procéder comme suit :

using namespace MyNamespace;

MyClass* pClass = new MyClass();

Modifier: Suite à quoi Bernhardrusch l'a dit, j'ai tendance à ne pas utiliser du tout la syntaxe "using namespace x", je spécifie généralement explicitement l'espace de noms lors de l'instanciation de mes objets (c'est-à-direle premier exemple que j'ai montré).

Et comme tu l'as demandé ci-dessous, vous pouvez utiliser autant d'espaces de noms que vous le souhaitez.

Autres conseils

Pour éviter de tout dire, Mark Ingram a déjà dit une petite astuce sur l'utilisation des espaces de noms :

Évitez la directive "using namespace" dans les fichiers d'en-tête - cela ouvre l'espace de noms pour toutes les parties du programme qui importent ce fichier d'en-tête.Dans les fichiers d'implémentation (*.cpp), cela ne pose normalement pas de gros problème - même si je préfère utiliser la directive "using namespace" au niveau de la fonction.

Je pense que les espaces de noms sont principalement utilisés pour éviter les conflits de noms – pas nécessairement pour organiser la structure de votre code.J'organiserais les programmes C++ principalement avec des fichiers d'en-tête/la structure des fichiers.

Parfois, les espaces de noms sont utilisés dans des projets C++ plus importants pour masquer les détails d'implémentation.

Remarque supplémentaire à la directive using :Certaines personnes préfèrent utiliser « using » uniquement pour des éléments uniques :

using std::cout;  
using std::endl;

Vincent Robert a raison dans son commentaire Comment utiliser correctement les espaces de noms en C++ ?.

Utiliser l'espace de noms

Les espaces de noms sont utilisés au minimum pour éviter les collisions de noms.En Java, cela est appliqué via l'idiome "org.domain" (car il est supposé que l'on n'utilisera rien d'autre que son propre nom de domaine).

En C++, vous pouvez donner un espace de noms à tout le code de votre module.Par exemple, pour un module MyModule.dll, vous pouvez donner à son code l'espace de noms MyModule.J'ai vu ailleurs quelqu'un utiliser MyCompany :: MyProject :: MyModule.Je pense que c'est exagéré, mais dans l'ensemble, cela me semble correct.

Utiliser "utiliser"

Using doit être utilisé avec beaucoup de précautions car il importe efficacement un (ou tous) symboles d'un espace de noms dans votre espace de noms actuel.

C'est mal de le faire dans un fichier d'en-tête car votre en-tête polluera toutes les sources qui l'incluent (cela me rappelle les macros...), et même dans un fichier source, mauvais style en dehors de la portée d'une fonction car il sera importé au niveau global les symboles de l’espace de noms.

La manière la plus sûre d'utiliser "using" consiste à importer des symboles sélectionnés :

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 d'espace de noms std"; dans le tutoriel ou les codes d'exemples.La raison est de réduire le nombre de symboles pour faciliter la lecture, et non pas parce que c'est une bonne idée.

"Utilisation de Namespace Std;" est découragé par Scott Meyers (je ne me souviens pas exactement quel livre, mais je peux le trouver si nécessaire).

Composition de l'espace de noms

Les espaces de noms sont plus que des packages.Un autre exemple peut être trouvé dans "The C++ Programming Language" de Bjarne Stroustrup.

Dans l'« Édition spéciale », à 8.2.8 Composition de l'espace de noms, il décrit comment fusionner deux espaces de noms AAA et BBB en 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 sélectionnés à partir de différents espaces de noms pour créer votre propre interface d'espace de noms personnalisée.Je n'ai pas encore trouvé d'utilisation pratique de cela, mais en théorie, c'est cool.

Je n'en ai vu aucune mention dans les autres réponses, voici donc mes 2 centimes canadiens :

Sur la rubrique "Utilisation de l'espace de noms", une instruction 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;

tu peux écrire:

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

N'écoutez pas tout le monde vous dire que les espaces de noms ne sont que des espaces de noms.

Ils sont importants car ils sont considérés par le compilateur comme appliquant le principe de l'interface.En gros, cela 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.Voici 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 car le paramètre impliquait déjà l'espace de noms.

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

namespace ns {

class A
{
};

}

void print(A a)
{
}

Et votre code peut commencer à appeler la fonction print(a) où vous le souhaitez.Imaginez maintenant que des années plus tard, l'auteur décide de fournir une fonction print(), meilleure que la vôtre car il connaît les composants internes de sa classe et peut créer une meilleure version que la vôtre.

Ensuite, les auteurs C++ ont décidé que sa version de la fonction print() devait être utilisée à la place de celle fournie dans un autre espace de noms, pour respecter le principe de l'interface.Et que cette "mise à niveau" de la fonction print() doit être aussi simple que possible, ce qui signifie que vous n'aurez pas à modifier chaque appel à la fonction print().C'est pourquoi les « fonctions d'interface » (fonctions 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 devez considérer un espace de noms C++ comme une "interface" lorsque vous en utilisez une et garder à l'esprit le principe de l'interface.

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

Les plus gros projets C++ que j'ai vus utilisaient à peine plus d'un espace de noms (par ex.booster la bibliothèque).

En fait, 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 placer uniquement l'interface publique dans le boost d'espace de noms de niveau supérieur.

Personnellement, je pense que plus une base de code s'agrandit, plus les espaces de noms deviennent importants, même au sein d'une seule application (ou bibliothèque).Au travail, nous plaçons chaque module de notre application dans son propre espace de noms.

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 fondamentalement la même chose que :

static const int CONSTANT = 42;

L'utilisation d'un espace de noms anonyme (au lieu d'un espace statique) est cependant la méthode recommandée pour que le code et les données soient visibles uniquement dans l'unité de compilation actuelle en C++.

Notez également que vous pouvez ajouter un espace de noms.C'est plus clair avec un exemple, ce que je veux dire c'est que tu peux 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.Ceci définit un seul espace de noms MyNamespace (c'est-à-dire que vous pouvez définir un seul espace de noms sur plusieurs fichiers).

En Java :

package somepackage;
class SomeClass {}

En C++ :

namespace somenamespace {
    class SomeClass {}
}

Et en les utilisant, Java :

import somepackage;

Et C++ :

using namespace somenamespace;

De plus, les noms complets sont « somepackge.SomeClass » pour Java et « somenamespace::SomeClass » pour C++.En utilisant ces conventions, vous pouvez vous organiser comme vous en avez l'habitude en Java, notamment en créant des noms de dossier correspondants pour les espaces de noms.Les exigences dossier-> package et fichier-> classe ne sont cependant pas là, vous pouvez donc nommer vos dossiers et classes indépendamment des packages et des espaces de noms.

Vous pouvez également contenir "using namespace..." dans une fonction par exemple :

void test(const std::string& s) {
    using namespace std;
    cout << s;
}

@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 -- (Est-ce que ça fait vraiment si longtemps ?) :Cet exemple particulier est désormais ambigu, comme Joey le souligne ci-dessous.Boost et standard : :maintenant chacun a un shared_ptr.]

De manière générale, je crée un espace de noms pour un corps de code si je pense qu'il pourrait y avoir des conflits de noms de fonctions ou de types avec d'autres bibliothèques.Cela aide également à coder la marque, ala booster:: .

Je préfère utiliser un espace de noms de niveau supérieur pour l'application et des sous-espaces de noms 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 soit utiliser "use NAMESPACE", qui est similaire à une instruction "import PACKAGE", par ex.utiliser la norme.Ou vous spécifiez le package comme préfixe de la classe séparé par "::", par exemple.std :: chaîne.Ceci est similaire à "java.lang.String" en Java.

Notez qu'un espace de noms en C++ n'est en réalité qu'un espace de noms.Ils ne fournissent aucune des encapsulations que font les packages en Java, vous ne les utiliserez donc probablement pas autant.

J'ai utilisé les espaces de noms C++ de la même manière qu'en C#, Perl, etc.C'est juste une séparation sémantique de symboles entre les éléments de bibliothèque standard, les éléments tiers et mon propre code.Je placerais ma propre application dans un espace de noms, puis un composant de bibliothèque réutilisable dans un autre espace de noms pour la séparation.

Une autre différence entre Java et C++ est qu'en C++, la hiérarchie des espaces de noms n'a pas besoin de correspondre à la disposition du système de fichiers.J'ai donc tendance à placer une bibliothèque entière réutilisable dans un seul espace de noms et les sous-systèmes de la bibliothèque dans des sous-répertoires :

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

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

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top