Domanda

Durante il refactoring di un vecchio codice ho eliminato una serie di metodi pubblici che in realtà avrebbero dovuto essere statici poiché a) non operano su nessun dato membro né chiamano altre funzioni membro eb) perché potrebbero rivelarsi utili altrove.

Ciò mi ha portato a pensare al modo migliore per raggruppare insieme le funzioni di "aiuto".Il metodo Java/C# sarebbe quello di utilizzare una classe di funzioni statiche con un costruttore privato, ad esempio:

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

Tuttavia, essendo C++ potresti anche utilizzare uno spazio dei nomi:

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

Nella maggior parte dei casi penso che preferirei l'approccio dello spazio dei nomi, ma volevo sapere quali sono i pro e i contro di ciascun approccio.Se ad esempio si utilizzasse l'approccio in classe, ci sarebbero dei costi generali?

È stato utile?

Soluzione

Il sovraccarico non è un problema, tuttavia gli spazi dei nomi presentano alcuni vantaggi

  • Puoi riaprire uno spazio dei nomi in un'altra intestazione, raggruppando le cose in modo più logicamente mantenendo basse le dipendenze di compilazione
  • Puoi utilizzare l'aliasing dello spazio dei nomi a tuo vantaggio (debug/rilascio, aiutanti specifici della piattaforma, ....)

    per esempio.Ho fatto cose del tipo

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

Altri suggerimenti

Un caso in cui si potrebbe usare class (O struct) Sopra namespace è quando è necessario un tipo, ad esempio:

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;
}

Per aggiungere all'eccellente risposta di Pieter, un altro vantaggio degli spazi dei nomi è che puoi inoltrare dichiarare cose che hai inserito in uno spazio dei nomi da qualche altra parte, in particolare le strutture...

//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);
};

E con gli spazi dei nomi...

//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);
};

Le dichiarazioni in avanti fanno una grande differenza nei tempi di compilazione dopo piccole modifiche all'intestazione una volta che ti ritrovi con un progetto che comprende centinaia di file sorgente.

Modifica da Paercebal

La risposta era troppo bella per lasciarla morire a causa di un errore di enumerazione (vedi commenti).Ho sostituito le enumerazioni (che possono essere dichiarate in avanti solo in C++0x, non nell'odierno C++) con struct.

Il vantaggio principale dell'utilizzo di uno spazio dei nomi è che puoi riaprirlo e aggiungere più elementi in seguito, cosa che non puoi fare con una classe.Ciò rende questo approccio migliore per gli helper liberamente accoppiati (ad esempio potresti avere uno spazio dei nomi Helpers per l'intera libreria, proprio come tutto STL è in ::std)

Il vantaggio principale di una classe è che puoi annidarla all'interno della classe che la utilizza, non puoi annidare uno spazio dei nomi in una classe.Ciò rende questo approccio migliore per gli aiutanti strettamente associati.

Non avrai alcun sovraccarico aggiuntivo avendoli in una classe rispetto a uno spazio dei nomi.

Gli spazi dei nomi offrono l'ulteriore vantaggio della ricerca Koenig.L'utilizzo delle classi helper può rendere il codice più dettagliato: in genere è necessario includere il nome della classe helper nella chiamata.

Un altro vantaggio degli spazi dei nomi è la leggibilità in seguito.Con le classi, devi includere parole come "Aiutante" per ricordarti in seguito che la classe particolare non viene utilizzata per creare oggetti

In pratica, non ci sono spese generali neanche in questo caso.Dopo la compilazione, cambia solo il nome utilizzato.

Parte della mia risposta copiata/ritagliata/rielaborata da Come si utilizzano correttamente gli spazi dei nomi in C++?.

Usando "usando"

Puoi usare "using" per evitare di ripetere il "prefisso" della tua funzione di supporto.Per esempio:

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
}

Composizione dello spazio dei nomi

Gli spazi dei nomi sono più che pacchetti.Un altro esempio può essere trovato in "The C++ Programming Language" di Bjarne Stroustrup.

Nella "Edizione Speciale", a 8.2.8 Composizione dello spazio dei nomi, descrive come unire due spazi dei nomi AAA e BBB in un altro chiamato CCC.Pertanto CCC diventa un alias sia per AAA che per BBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

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

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

Potresti anche importare simboli selezionati da diversi spazi dei nomi, per creare la tua interfaccia personalizzata dello spazio dei nomi.Devo ancora trovarne un uso pratico, ma in teoria è bello.

Tendo a utilizzare spazi dei nomi anonimi durante la creazione di funzioni di supporto.Dato che dovrebbero (generalmente) essere visti solo dal modulo che se ne prende cura, è un buon modo per controllare le dipendenze.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top