Pregunta

Mientras refactorizaba algún código antiguo, eliminé una serie de métodos públicos que en realidad deberían haber sido estáticos ya que a) no operan con ningún dato de miembro ni llaman a ninguna otra función miembro yb) porque podrían resultar útiles en otros lugares.

Esto me llevó a pensar en la mejor manera de agrupar las funciones "ayudantes".La forma Java/C# sería utilizar una clase de funciones estáticas con un constructor privado, por ejemplo:

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

Sin embargo, al ser C++ también puedes usar un espacio de nombres:

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

En la mayoría de los casos, creo que preferiría el enfoque del espacio de nombres, pero quería saber cuáles son los pros y los contras de cada enfoque.Si se utilizara el enfoque de clases, por ejemplo, ¿habría gastos generales?

¿Fue útil?

Solución

Los gastos generales no son un problema, aunque los espacios de nombres tienen algunas ventajas

  • Puede reabrir un espacio de nombres en otro encabezado, agrupando las cosas más lógicamente mientras mantiene bajas las dependencias de compilación
  • Puede usar alias en el espacio de nombres para su ventaja (depuración/versión, ayudantes específicos de la plataforma, ....)

    p.ej.He hecho cosas como

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

Otros consejos

Un caso en el que se podría utilizar class (o struct) encima namespace es cuando uno necesita un tipo, por ejemplo:

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

Para agregar a la excelente respuesta de Pieter, otra ventaja de los espacios de nombres es que puedes reenviar declarar cosas que colocas en un espacio de nombres en otro lugar, especialmente estructuras...

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

Y con espacios de nombres...

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

Las declaraciones hacia adelante marcan una gran diferencia en los tiempos de compilación después de pequeños cambios en el encabezado una vez que terminas con un proyecto que abarca cientos de archivos fuente.

Editar desde paercebal

La respuesta era demasiado buena para dejarla morir debido a un error de enumeración (ver comentarios).Reemplacé enumeraciones (que pueden declararse hacia adelante solo en C++ 0x, no en C++ actual) por estructuras.

La principal ventaja de usar un espacio de nombres es que puedes volver a abrirlo y agregar más cosas más tarde, no puedes hacer eso con una clase.Esto hace que este enfoque sea mejor para los asistentes poco acoplados (por ejemplo, podría tener un espacio de nombres de asistentes para toda su biblioteca, de manera muy similar a como todo STL está en ::std)

La principal ventaja de una clase es que puedes anidarla dentro de la clase usándola, no puedes anidar un espacio de nombres en una clase.Esto hace que este enfoque sea mejor para ayudantes estrechamente acoplados.

No tendrá ningún gasto adicional al tenerlos en una clase frente a un espacio de nombres.

Los espacios de nombres ofrecen la ventaja adicional de la búsqueda Koenig.El uso de clases auxiliares puede hacer que su código sea más detallado; por lo general, deberá incluir el nombre de la clase auxiliar en la llamada.

Otro beneficio de los espacios de nombres es la legibilidad posterior.Con las clases, debes incluir palabras como "Ayudante" para recordarte más adelante que la clase en particular no se usa para crear objetos.

En la práctica, tampoco hay gastos generales.Después de la compilación, sólo difiere el nombre utilizado.

Copié/recorté/reelaboré parte de mi respuesta de ¿Cómo se utilizan correctamente los espacios de nombres en C++?.

Usando "usando"

Puede utilizar "usar" para evitar repetir el "prefijo" de su función auxiliar.Por ejemplo:

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
}

Composición del espacio de nombres

Los espacios de nombres son más que paquetes.Otro ejemplo se puede encontrar en "El lenguaje de programación C++" de Bjarne Stroustrup.

En la "Edición Especial", en 8.2.8 Composición del espacio de nombres, describe cómo se pueden fusionar dos espacios de nombres AAA y BBB en otro llamado CCC.Así, CCC se convierte en un alias tanto para AAA como para BBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

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

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

Incluso podría importar símbolos seleccionados de diferentes espacios de nombres para crear su propia interfaz de espacio de nombres personalizada.Todavía tengo que encontrar un uso práctico para esto, pero en teoría es genial.

Tiendo a utilizar espacios de nombres anónimos al crear funciones auxiliares.Dado que (generalmente) sólo deberían ser vistos por el módulo que se preocupa por ellos, es una buena forma de controlar las dependencias.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top