C ++: espacios de nombres: ¿cómo utilizarlos correctamente en los archivos fuente y de encabezado?


88

Considere un par de dos archivos fuente: un archivo de declaración de interfaz ( *.ho *.hpp) y su archivo de implementación ( *.cpp).

Deje que el *.harchivo sea como el siguiente:

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

He visto dos prácticas diferentes para usar espacios de nombres en archivos fuente:

*.cpp mostrando la práctica # 1:

#include "MyClass.h"
using namespace MyNamespace;

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

*.cpp mostrando la práctica # 2:

#include "MyClass.h"
namespace MyNamespace {

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

}

Mi pregunta: ¿Existen diferencias entre estas dos prácticas y se considera que una es mejor que la otra?


30
También existe la opción 3: solo usamos el nombre completo, por ejemplo int MyNamespace::MyClass::foo() ....
— Benjamin Bannier


@Dave no duplicar. Estas preguntas se complementan entre sí. Recomiende agregar el enlace proporcionado por Dave como "Leer también ..." a esta pregunta. Mi pregunta ayudará a los principiantes a elegir el estilo correcto.
— nickolay

Respuestas:


62

Desde el punto de vista de la legibilidad del código, probablemente sea mejor, en mi opinión, usar el método # 2 por esta razón:

Puede haber usingvarios espacios de nombres a la vez, y cualquier objeto o función escrito debajo de esa línea puede pertenecer a cualquiera de esos espacios de nombres (salvo conflictos de nombres). Envolver todo el archivo en un namespacebloque es más explícito y le permite declarar nuevas funciones y variables que pertenecen a ese espacio de nombres dentro del archivo .cpp también


La pregunta que Dave vinculó en su comentario a su pregunta también describe algunos puntos clave en las diferencias (si las hay) entre los dos métodos que está viendo
— Dan F

Chicos, realmente no sé de quién elegir la respuesta. Tienen intersección mientras se complementan.
— nickolay

Solo comentando para reconocer que algunos IDE como CLion solo detectarán implementaciones si usa la opción / práctica # 2.
— PedroTanaka

@PedroTanaka, ¿sigue siendo así? No he notado tal problema.
— John McFarlane

@JMcF No he verificado desde el momento en que publiqué el comentario. En las primeras versiones de Clion ocurría el problema.
— PedroTanaka

51

La más clara es la opción que no mostró:

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

También es muy detallado; demasiado para la mayoría de la gente. Dado que using namespacees una receta para los conflictos de nombres, al menos en mi experiencia, y debe evitarse, excepto en ámbitos y lugares muy limitados, generalmente uso su # 2.


3
Gracias muy claro. Juntos creamos una buena página de preguntas frecuentes para los usuarios de espacios de nombres. :)
— nickolay

2
Chicos, realmente no sé de quién elegir la respuesta. Tienen intersección mientras se complementan.
— nickolay

10

¿Existen diferencias entre estas dos prácticas?

Si. # 1 y # 2 son ejemplos de una directiva using y una definición de espacio de nombres respectivamente. Son efectivamente iguales en este caso, pero tienen otras consecuencias. Por ejemplo, si introduce un nuevo identificador al lado MyClass::foo, tendrá un alcance diferente:

# 1:

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

# 2:

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

¿Se considera uno mejor que el otro?

Pros # 1: un poco más conciso; más difícil introducir accidentalmente algo enMyNamespace sin saberlo. Contras: puede extraer identificadores existentes de forma involuntaria.

# 2 Pros: es más claro que las definiciones de identificadores existentes y las declaraciones de identificadores nuevos pertenecen a ambas MyNamespace. Contras: es más fácil introducir identificadores de forma involuntaria MyNamespace.

Una crítica tanto del n. ° 1 como del n. ° 2 es que se refieren a un espacio de nombres completo cuando probablemente solo le interese la definición de miembros de MyNamespace::MyClass . Esto es torpe y comunica mal la intención.

Una posible alternativa al n. ° 1 es una declaración de uso que incluye solo el identificador que le interesa:

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

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

4

También me gustaría agregar que si, por alguna razón, decide implementar una especialización de plantilla en un archivo cpp y simplemente confía en using namespaceque se encontrará con el siguiente problema:

// .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(){}

De lo contrario, si aplica el método n. ° 2, estará bien.


0

Me gustaría agregar una forma más, usando using-statement :

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

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

De esta manera, le ahorra escribir el nombre del espacio de nombres muchas veces si la clase tiene muchas funciones

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.