Je viens d'un arrière-plan Java, où les packages sont utilisés, pas des espaces de noms. J'ai l'habitude de mettre 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 utilisez-vous les espaces de noms en C ++? Créez-vous un seul espace de noms pour toute l'application ou créez-vous des espaces de noms pour les principaux composants? Si oui, comment créez-vous des objets à partir de classes dans d'autres espaces de noms?
la source
std
espace de noms aux symboles plutôt qu'à utiliserusing
du tout. Donc j'écris toujoursstd::cout
oustd::string
maintenant parce que c'est comme ça que je les appelle maintenant. Je n'écrirais jamaiscout
.std
, j'ai personnellement trouvé cela beaucoup moins important lorsque vous traitez avec des bibliothèques plus petites. Souvent, vous pouvez simplement utiliserusing namespace FooBario;
, en particulier si vous utilisez un nombre considérable de types d'une bibliothèque.using namespace X;
devrait être évité dans les fichiers d'en-tête si possible.mylibrary::endl
pour représenter ma propre séquence spéciale de nouvelle ligne. Je veux dire, pourquoi inventer des noms?Pour éviter de tout dire, Mark Ingram a déjà dit un petit conseil pour utiliser les 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), ce n'est normalement pas un 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 votre structure de code. J'organiserais des 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 gros pour masquer les détails de l'implémentation.
Remarque supplémentaire sur la directive using: Certaines personnes préfèrent utiliser "using" uniquement pour des éléments uniques:
la source
using std::cout;
est une déclaration d'utilisationusing std::cout, std::endl;
ou mêmeusing std::cout, endl;
,.using namespace x
dans un en-tête s'il se trouve dans un autre espace de noms. Ce n'est pas quelque chose que je recommanderais en général, mais cela ne pollue pas l'espace de noms global.Vincent Robert a raison dans son commentaire Comment utilisez-vous correctement les espaces de noms en C ++? .
Utiliser l'espace de noms
Les espaces de noms sont utilisés à tout le moins pour éviter la collision de noms. En Java, cela est imposé par 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 nom MyModule. J'ai vu ailleurs quelqu'un utiliser MyCompany :: MyProject :: MyModule. Je suppose que c'est exagéré, mais dans l'ensemble, cela me semble correct.
Utiliser "en utilisant"
L'utilisation doit être utilisée avec le plus grand soin car elle 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 y compris (cela me rappelle les macros ...), et même dans un fichier source, mauvais style en dehors d'une portée de fonction car il importera à portée globale les symboles de l'espace de noms.
La façon la plus sûre d'utiliser "à l'aide de" est d'importer certains symboles:
Vous verrez beaucoup de "using namespace std;" dans des tutoriels ou des exemples de codes. La raison est de réduire le nombre de symboles pour faciliter la lecture, non pas parce que c'est une bonne idée.
"using 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 "Le langage de programmation C ++" de Bjarne Stroustrup.
Dans la "Special Edition", au 8.2.8 Composition des espaces de noms , il décrit comment vous pouvez fusionner deux espaces de noms AAA et BBB en un autre appelé CCC. Ainsi, CCC devient un alias pour AAA et BBB:
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é une utilisation pratique de cela, mais en théorie, c'est cool.
la source
Je n'en ai vu aucune mention dans les autres réponses, voici donc mes 2 cents canadiens:
Sur la rubrique "Utilisation de l'espace de noms", une déclaration utile est l'alias d'espace de noms, vous permettant de "renommer" un espace de noms, normalement pour lui donner un nom plus court. Par exemple, au lieu de:
tu peux écrire:
la source
N'écoutez pas toutes les personnes 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 d'interface. Fondamentalement, cela peut être expliqué par un exemple:
Si vous vouliez imprimer un objet A, le code serait celui-ci:
Notez que nous n'avons pas mentionné explicitement 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 car le paramètre impliquait déjà l'espace de noms.
Maintenant, pourquoi ce principe est 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.
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 internes de sa classe et peut faire une meilleure version que la vôtre.
Les auteurs C ++ ont alors 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 d'interface. Et que cette "mise à niveau" 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 espace de noms C ++ comme une "interface" lorsque vous en utilisez un et garder à l'esprit le principe de l'interface.
Si vous voulez une meilleure explication de ce comportement, vous pouvez vous référer au livre Exceptional C ++ de Herb Sutter
la source
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 ne mettre que l'interface publique dans le boost d'espace de noms de niveau supérieur.
Personnellement, je pense que plus une base de code est grande, plus les espaces de noms deviennent importants, même au sein d'une seule application (ou bibliothèque). Au travail, nous mettons 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:
C'est essentiellement la même chose que:
L'utilisation d'un espace de noms anonyme (au lieu de statique) est cependant la méthode recommandée pour que le code et les données ne soient visibles que dans l'unité de compilation actuelle en C ++.
la source
const int CONSTANT = 42;
car la constante de niveau supérieur dans une étendue d'espace de noms implique déjà une liaison interne. Vous n'avez donc pas besoin de l'espace de noms anonyme dans ce cas.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 vous pouvez avoir:
dans un fichier
square.h
, etdans un fichier
cube.h
. Cela définit un seul espace de nomsMyNamespace
(c'est-à-dire que vous pouvez définir un seul espace de noms sur plusieurs fichiers).la source
En Java:
En C ++:
Et en les utilisant, Java:
Et C ++:
De plus, les noms complets sont "somepackge.SomeClass" pour Java et "somenamespace :: SomeClass" pour C ++. En utilisant ces conventions, vous pouvez 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 de dossier-> package et file-> class ne sont pas là, donc vous pouvez nommer vos dossiers et classes indépendamment des packages et des espaces de noms.
la source
@ marius
Oui, vous pouvez utiliser plusieurs espaces de noms à la fois, par exemple:
[Fév. 2014 - (Cela fait-il vraiment si longtemps?): Cet exemple particulier est maintenant ambigu, comme le souligne Joey ci-dessous. Boost et std :: maintenant ont chacun un shared_ptr.]
la source
std
également le casshared_ptr
maintenant, donc l'utilisation des deuxboost
et desstd
espaces de noms se heurtera lorsque vous essayez d'utiliser unshared_ptr
.Vous pouvez également contenir "using namespace ..." dans une fonction par exemple:
la source
De manière générale, je crée un espace de noms pour un corps de code si je pense qu'il peut y avoir des conflits de noms de fonctions ou de types avec d'autres bibliothèques. Il aide également à marquer le code, ala boost :: .
la source
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 des classes à partir 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 exemple use std. Ou vous spécifiez le package comme préfixe de la classe séparée par "::", par exemple std :: string. Ceci est similaire à "java.lang.String" en Java.
la source
Notez qu'un espace de noms en C ++ n'est vraiment 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.
la source
J'ai utilisé des espaces de noms C ++ de la même manière que je le fais en C #, Perl, etc. C'est juste une séparation sémantique de symboles entre des éléments de bibliothèque standard, des é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.
la source
Une autre différence entre java et C ++ est qu'en C ++, la hiérarchie de l'espace de noms n'a pas besoin de mach la disposition du système de fichiers. J'ai donc tendance à mettre une bibliothèque réutilisable entière dans un seul espace de noms et des sous-systèmes dans la bibliothèque dans des sous-répertoires:
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.
la source