web-dev-qa-db-fra.com

C++: Namespaces - Comment utiliser correctement les fichiers d'en-tête et les fichiers source?

Prenons une paire de deux fichiers sources: un fichier de déclaration d'interface (*.h ou *.hpp) et son fichier d'implémentation (*.cpp).

Laissez le fichier *.h ressembler à ceci:

namespace MyNamespace {
  class MyClass {
  public:
    int foo();
  };
}

J'ai observé deux pratiques différentes d'utilisation des espaces de nom dans les fichiers source:

*.cpp montrant la pratique n ° 1:

#include "MyClass.h"
using namespace MyNamespace;

int MyClass::foo() { ... }

*.cpp montrant la pratique n ° 2:

#include "MyClass.h"
namespace MyNamespace {

  int MyClass::foo() { ... }

}

Ma question: Y a-t-il des différences entre ces deux pratiques et l'une est-elle considérée meilleure que l'autre?

66
DaddyM

Du point de vue de la lisibilité du code, il est probablement préférable, à mon avis, d’utiliser la méthode n ° 2 pour cette raison: 

Vous pouvez être using plusieurs espaces de nom à la fois, et tout objet ou fonction écrit au-dessous de cette ligne peut appartenir à l'un de ces espaces (sauf en cas de conflit de noms). Envelopper le fichier entier dans un bloc namespace est plus explicite et vous permet de déclarer également les nouvelles fonctions et variables qui appartiennent à cet espace de noms dans le fichier .cpp.

51
Dan F

Le plus clair est l'option que vous n'avez pas montrée:

int MyNamespace::MyClass::foo()
{
    //  ...
}

C'est aussi très verbeux; trop pour la plupart des gens. Puisque using namespace recrée les conflits de noms, du moins selon mon expérience, Et devrait être évité sauf dans des portées et des lieux très limités, j’utilise généralement votre # 2. 

41
James Kanze

Y a-t-il des différences entre ces deux pratiques

Oui. N ° 1 et N ° 2 sont des exemples de using-directive et de - namespace definition respectivement. Ils sont effectivement les mêmes dans ce cas mais ont d'autres conséquences. Par exemple, si vous introduisez un nouvel identifiant à côté de MyClass::foo, sa portée sera différente:

#1:

using namespace MyNamespace;
int x;  // defines ::x

# 2:

namespace MyNamespace {
  int x;  // defines MyNamespace::x
}

l'un est-il considéré comme meilleur que l'autre?

# 1 Avantages: un peu plus laconique; plus difficile d’introduire accidentellement quelque chose dans MyNamespace sans le vouloir. Inconvénients: peut extraire involontairement des identifiants existants. 

# 2 Avantages: il est plus clair que les définitions d’identifiants existants et les déclarations de nouveaux identifiants appartiennent à MyNamespace. Inconvénients: il est plus facile d’introduire involontairement des identifiants dans MyNamespace.

Une critique des N ° 1 et N ° 2 est qu'ils font référence à un espace de noms entier alors que vous ne vous souciez probablement que de la définition des membres de MyNamespace::MyClass. C’est une lourde main qui communique mal l’intention. 

Une alternative possible à # 1 est un using-declaration qui ne contient que l'identifiant qui vous intéresse:

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }
5
John McFarlane

J'aimerais également ajouter que si vous décidez, pour une raison quelconque, d'implémenter une spécialisation de modèle dans un fichier cpp et que vous vous appuyez simplement sur using namespace, le problème suivant se posera:

// .h file
namespace someNameSpace
{
  template<typename T>
    class Demo
    {
      void foo();
    };
}

// .cpp file
using namespace someNameSpace;

template<typename T>
void Demo<T>::foo(){}

// this will produce
// error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive]
template<>
void Demo<int>::foo(){}

Sinon, si vous appliquez la méthode n ° 2, tout ira bien.

3
Jordan

J'aimerais ajouter un moyen supplémentaire, en utilisant using-declaration :

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }

De cette façon, vous éviterez de saisir le nom de l’espace de nom plusieurs fois si la classe a plusieurs fonctions

0
Joanna