Question

Tout en refacturant un ancien code, j'ai supprimé un certain nombre de méthodes publiques qui devraient en réalité être de la statique car elles: a) ne traitent aucune donnée membre ni n'appellent aucune autre fonction membre et b) car elles pourraient s'avérer utiles ailleurs .

Cela m’a amené à réfléchir à la meilleure façon de regrouper les fonctions d’aide. La méthode Java / C # consisterait à utiliser une classe de fonctions statiques avec un constructeur privé, par exemple:

.
class Helper  
{  
private:  
  Helper() { }
public:  
  static int HelperFunc1();  
  static int HelperFunc2();  
};

Cependant, étant C ++, vous pouvez également utiliser un espace de noms:

namespace Helper  
{  
  int HelperFunc1();  
  int HelperFunc2();  
}

Dans la plupart des cas, je préférerais l’approche par l’espace de nommage, mais je voulais savoir quels étaient les avantages et les inconvénients de chaque approche. Si on utilisait l'approche de classe par exemple, y aurait-il des frais généraux?

Était-ce utile?

La solution

Les frais généraux ne sont pas un problème, les espaces de noms présentent toutefois certains avantages

  • Vous pouvez rouvrir un espace de noms dans un autre en-tête, en regroupant les éléments plus logiquement garder les dépendances de compilation basses
  • Vous pouvez utiliser l'alias d'espace de nom à votre avantage (débogage / libération, aides spécifiques à la plate-forme, ....)

    par exemple. J'ai fait des choses comme

    namespace LittleEndianHelper {
       void Function();
    }
    namespace BigEndianHelper {
       void Function();
    }
    
    #if powerpc
       namespace Helper = BigEndianHelper;
    #elif intel
       namespace Helper = LittleEndianHelper;
    #endif
    

Autres conseils

Un cas dans lequel on pourrait utiliser classe (ou struct ) sur espace de noms est celui qui nécessite un type, par exemple:

struct C {
  static int f() { return 33; }
};

namespace N {
  int f() { return 9; }
}

template<typename T>
int foo() {
  return T::f();
}

int main() {
  int ret = foo<C>();
//ret += foo<N>(); // compile error: N is a namespace
  return ret;
}

Pour ajouter à l'excellente réponse de Pieter, un autre avantage des espaces de noms est que vous pouvez transférer les éléments de déclaration que vous avez placés dans un espace de noms, en particulier les structs ...

//Header a.h
// Lots of big header files, spreading throughout your code
class foo
{
  struct bar {/* ... */);
};

//header b.h
#include a.h // Required, no way around it, pulls in big headers
class b
{
  //...
  DoSomething(foo::bar);
};

Et avec les espaces de noms ...

//Header a.h
// Big header files
namespace foo
{
  struct bar {/* ... */);
}

//header b.h
// Avoid include, instead forward declare 
//  (can put forward declares in a _fwd.h file)
namespace foo
{
  struct bar;
}

class b
{
  //...
  // note that foo:bar must be passed by reference or pointer
  void DoSomething(const foo::bar & o);
};

Les déclarations suivantes font une grande différence dans les temps de compilation après la modification de petits en-têtes lorsque vous vous retrouvez avec un projet couvrant des centaines de fichiers sources.

Modifier depuis paercebal

La réponse était trop bonne pour le laisser mourir à cause d’une erreur d’énumération (voir commentaires). J'ai remplacé les énumérations (qui ne peuvent être déclarées en aval que dans C ++ 0x, pas dans C ++ actuel) par des structures.

Le principal avantage de l'utilisation d'un espace de noms est que vous pouvez le rouvrir et ajouter d'autres éléments ultérieurement, vous ne pouvez pas le faire avec une classe. Cela rend cette approche meilleure pour les helpers faiblement couplés (par exemple, vous pourriez avoir un espace de noms Helpers pour toute votre bibliothèque, comme si tout le fichier STL était dans :: std)

L'avantage principal d'une classe est que vous pouvez l'imbriquer dans la classe en l'utilisant. Vous ne pouvez pas imbriquer un espace de nom dans une classe. Cela rend cette approche meilleure pour les assistants étroitement couplés.

Vous n'aurez aucune surcharge supplémentaire à les avoir dans une classe par rapport à un espace de noms.

Les espaces de noms offrent l’avantage supplémentaire de la recherche Koenig. L'utilisation de classes auxiliaires peut rendre votre code plus détaillé - vous devez généralement inclure le nom de la classe auxiliaire dans l'appel.

Un autre avantage des espaces de noms est la lisibilité ultérieure. Avec les classes, vous devez inclure des mots tels que "Helper". pour vous rappeler plus tard que cette classe n'est pas utilisée pour créer des objets

En pratique, il n'y a pas de frais généraux non plus. Après la compilation, seul le nom utilisé est différent.

Copie / correction / reprise d'une partie de ma réponse à partir de Comment utilisez-vous correctement les espaces de noms en C ++? .

Utilisation de "Utilisation de"

Vous pouvez utiliser " utiliser " pour éviter de répéter le " préfixage " de votre fonction d'assistance. par exemple:

struct AAA
{
   void makeSomething() ;
} ;

namespace BBB
{
   void makeSomethingElse() ;
}

void willCompile()
{
   AAA::makeSomething() ;
   BBB::makeSomethingElse() ;
}

void willCompileAgain()
{
   using BBB ;

   makeSomethingElse() ; // This will call BBB::makeSomethingElse()
}

void WONT_COMPILE()
{
   using AAA ; // ERROR : Won't compile

   makeSomething() ; // ERROR : Won't compile
}

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 "Special Edition", sous 8.2.8 Composition de l'espace de nommage , il explique comment fusionner deux espaces de nommage 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 de sélection à partir d'espaces de noms différents pour créer votre propre interface d'espace de noms personnalisée. Je n'ai pas encore trouvé d'utilisation pratique, mais en théorie, c'est cool.

J'ai tendance à utiliser des espaces de noms anonymes lors de la création de fonctions d'assistance. Puisqu'ils ne devraient (généralement) être vus que par le module qui les concerne, c'est un bon moyen de contrôler les dépendances.

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