2009-04-03 13 views
69

Me estoy enseñando C++ namespaces (viniendo de un fondo de C#) y realmente estoy empezando a pensar que incluso con todo lo que C++ hace mejor que la mayoría de los otros lenguajes, namespaces anidados no es uno ¡de ellos!C++ namespaces advice

Estoy en lo cierto al pensar que el fin de declarar algunos espacios de nombres anidados que tengo que hacer lo siguiente:

namespace tier1 
{ 
    namespace tier2 
    { 
     namespace tier3 
     { 
      /* then start your normal code nesting */ 
     } 
    } 
} 

A diferencia:

namespace tier1::tier2::tier3 
{ 
} 

a la C#?

Esto se hace aún más demente cuando necesito para reenviar declarar:

namespace tier1 
{ 
    namespace tier2 
    { 
     namespace forward_declared_namespace 
     { 
      myType myVar; // forward declare 
     } 
     namespace tier3 
     { 
      /* then start your normal code nesting */ 
      class myClass 
      { 
       forward_declared_namespace::myType myMember; 
      } 
     } 
    } 
} 

Teniendo en cuenta que un sistema típico que desarrollo se compone de:

MyCompany::MySolution::MyProject::System::[PossibleSections]::Type 

¿Es por eso que no lo hace ¿tienden a ver mucho uso de espacios de nombres en ejemplos de C++? ¿O generalmente solo espacios de nombres individuales (no anidados)?

ACTUALIZACIÓN

Para cualquier persona interesada, this is how I ended up hacer frente a este problema.

+2

Finalmente, C++ 17 permitirá 'namespace tier1 :: tier2 :: tier3'. –

+3

El enlace en la actualización está roto ... – AlwaysLearning

+0

Me interesó saber cómo abordó el problema e hice clic en su enlace. Por desgracia, como ya ha señalado AlwaysLearning, el enlace se rompió. – csj

Respuesta

103

C++ espacios de nombres no estaban destinados a ser un mecanismo de diseño - que están ahí simplemente para evitar conflictos de nombres. Realmente no desea o necesita utilizar espacios de nombres anidados en el 99.99% de las situaciones.

Un buen ejemplo del uso correcto de espacios de nombres en C++ es la Biblioteca estándar de C++. Todo en esta biblioteca bastante grande se coloca en un solo espacio de nombre llamado std - no hay ningún intento o necesidad de dividir la biblioteca en (por ejemplo) un espacio de nombres secundario de E/S, un espacio de nombres matemático, un contenedor secundario -nombre de espacio, etc.

La herramienta básica para modelar en C++ es la clase (y hasta cierto punto la plantilla), no el espacio de nombres. Si usted siente la necesidad de anidación, se debe considerar el uso de clases anidadas, que tienen las siguientes ventajas sobre los espacios de nombres:

  • tienen métodos
  • que pueden controlar el acceso
  • que no se pueden volver a abrir

Habiendo considerado esto, si aún desea utilizar espacios de nombres anidados, hágalo de todas formas; no hay nada técnicamente incorrecto al usarlos de esta manera.

+15

no pretendían ser un mecanismo mpl. Pero los chicos los usan de esa manera. –

+0

Buen consejo como siempre mr. ¡butterworth! –

+0

¿Es bueno nombrar clases como DAOUser DAOPacient VIEWUser MODELUser, etc. –

22

Los espacios de nombres de C++ fueron una gran mejora con respecto a la oferta anterior (es decir, no espacios de nombres en absoluto). Los espacios de nombres de C# han extendido el concepto y han corrido con él. Te aconsejo que mantengas tus espacios de nombres en una estructura simple y plana.

EDIT¿Lo aconseja debido a los inconvenientes que he descrito aquí?

Simplemente "Sí". Los espacios de nombres C++ no fueron diseñados para ayudarlo a particionar sus bibliotecas lógicas & de la manera en que lo hacen en C#.

El propósito de los espacios de nombres C++ es detener el problema del mundo real encontrado por los desarrolladores de C, donde experimentan colisiones de nombres cuando utilizan dos bibliotecas de terceros que exportan los mismos nombres de función. Los desarrolladores de C tenían varias soluciones para ello, pero podría ser un dolor serio.

La idea era que el STL, etc tiene el espacio de nombres std::, librerías proporcionadas por "XYZ Corp" tendrían un espacio de nombres xyz::, que trabaja para "ABC Corp" pondría toda su materia en un único espacio de nombres abc::.

+1

¿Aconsejas eso debido a los inconvenientes que he descrito aquí? –

4

En primer lugar, puede evitar la sangría del espacio de nombres, porque no hay ninguna razón para eso.

El uso de espacios de nombres en los ejemplos no mostrará la energía de los espacios de nombres. Y su poder como para mí está dividiendo las áreas de dominio una de otra. Divida las clases de utilidad de las comerciales.

Simplemente no mezcle diferentes jerarquías de espacio de nombres en el archivo .h. Los espacios de nombres son un tipo de comentario adicional para su interfaz de declaración de funciones. Buscar en los espacios de nombres y los nombres de las clases debería explicar muchas cosas.

namespace product 
{ 
namespace DAO 
{ 

class Entity 
{ 
}; 
+2

"En primer lugar, puede evitar la sangría del espacio de nombres, porque no hay ninguna razón para eso". eso es exactamente lo que realmente hago;) –

+0

Gran punto, y creo que el poder del espacio de nombres se amplifica aún más cuando se usan las herramientas [CASE] (http://en.wikipedia.org/wiki/Computer-aided_software_engineering) para visualizar las relaciones y capas de la base del código . Herramientas como [CppDepend] (http://www.cppdepend.com/) o el [Dependency Graph] de Visual Studio (http://msdn.microsoft.com/en-us/library/dd409453.aspx) toman tal desarrollador creado " comprensibilidad del código "que están estructurados a través de todos los anidamientos del espacio de nombres para iluminar realmente las capas y las dependencias de una manera coherente y bien estructurada. Las plantillas – jxramos

-1

Estás sobreutilizándolos (y no obtendrás nada a cambio).

+14

Una estructura jerárquica ordenada. (Re "no obtendrá nada a cambio") Creo que esto es enorme, y muy subestimado en C++. Solo piense en cómo esto impacta en la documentación. –

+0

@Konrad Estoy completamente de acuerdo – doc

+1

@Konrad, creo que esta es la esencia de mi pregunta. –

7

Al menos como una pequeña ayuda, en algunos casos se puede hacer esto:

namespace foo = A::B::C::D; 

y luego hacer referencia A :: B :: C :: D como foo. Pero solo en algunos casos

+2

¿En qué casos no puedes hacer eso? – anthropomorphic

17

lo que hago cuando se declara hacia adelante se ve así:

namespace abc { namespace sub { namespace subsub { class MyClass; }}} 

Mis declaraciones adelantadas se derrumbó en una sola línea. La legibilidad de la declaración directa se sacrifica a cambio de la legibilidad del resto del código. Y para las definiciones No consumo hendiduras o bien:

namespace abc { 
namespace sub { 
namespace subsub { 

class MyClass 
{ 
    public: 
     MyClass(); 

     void normalIntendationsHere() const; 
}; 

} 
} 
} 

El uso de este estilo requiere un poco de disciplina al principio, pero es el mejor compromiso para mí.

+7

Esta no es una respuesta a la pregunta formulada. – Jamer

+1

@Jammer: era nuevo en stackoverflow y no tuve la idea :) Sry. – doc

+2

No obstante, son buenos puntos. –

4

Puede omitir la sangría. A menudo escribo

namespace myLib { namespace details { 

/* source code */ 

}; }; /* myLib::details */ 

código fuente de C++ se compila en tiempo binario, a diferencia de C#/Java, que se queda en el binario. Por lo tanto, el espacio de nombres solo proporciona una solución fina para el conflicto de nomenclatura variable. No está destinado a la jerarquía de clases.

A menudo guardo uno o dos niveles de espacio de nombres en el código.

+25

Los puntos y comas no son necesarios. – alexk7

-1

veces Declaro profundos espacios de nombres como un par de macros en una cabecera separada

espacio de nombres.h

#define NAMESPACE_TIER1_TIER2_TIER3 \ 
    namespace tier1 { \ 
    namespace tier2 { \ 
    namespace tier3 { 

#define END_NAMESPACE_TIER1_TIER2_TIER3 }}} 

Para usarlo en otro lugar:

anotherfile.h

#include "./namespace.h" 

NAMESPACE_TIER1_TIER2_TIER3; 

/* Code here */ 

END_NAMESPACE_TIER1_TIER2_TIER3; 

Los puntos y comas redundante después de la macro son para evitar la sangría adicional.

+2

eso es realmente complicado y deberías definirlo para cada espacio de nombres anidado. Además, si va a escribir 'NAMESPACE_TIER1_TIER2_TIER3' y' END_NAMESPACE_TEIR1_TIER2_TIER3', ¿por qué no simplemente escribe 'namespace tier1 {namespace tier2 {namespace tier3 {' and '}}}'? En total, es en realidad más corto. – anthropomorphic

+0

No estoy de acuerdo, no es más corto y crea un problema de sangría muy profundo. He intentado ambos y prefiero el método #define. Editar: bien, menos el problema de sangría ... – icecream

+1

Prefiere lo que te gusta, pero no recomendaría eso a otros usuarios. No es más corto (como puede ver en mi comentario, donde los dos están alineados) y eso sin contar la definición, y ciertamente es más difícil hacer un seguimiento de los errores de esa manera. ¿Qué pasa si haces un error tipográfico? El compilador no sabrá qué es lo que está mal y su error aparecerá completamente en el lugar equivocado. – anthropomorphic

1

He encontrado que puedes ordenar el espacio de nombres C# de esta manera;

namespace ABC_Maths{ 
    class POINT2{}; 
    class Complex{}; 
} 

namespace ABC_Maths_Conversion{ 
    ABC_MATHS::Complex ComplexFromPOINT2(ABC_MATHS::POINT2) 
    {return new ABC_MATHS::Complex();} 

    ABC_MATHS::POINT4 POINT2FromComplex(ABC_MATHS::COMPLEX) 
    {return new ABC_MATHS::POINT2();} 
} 

namespace ABC 
{ 
} 

Pero el código no parece ser muy ordenado. Y esperaría a tener uso de largo aliento

Es mejor nido tanta funcionalidad en clases algo así como

namespace ABC{ 
    class Maths{ 
     public: 
     class POINT2{}; 
     class Complex:POINT2{}; 
     class Conversion{ 
      public: 
      static Maths.Complex ComplexFromPOINT2(MATHS.POINT2 p) 
      {return new MATHS.Complex();} 

      static MATHS.POINT2 POINT2FromComplex(MATHS.COMPLEX p) 
      {return new ABC::MATHS.POINT2();}// Can reference via the namespace if needed 
} /*end ABC namespace*/ 

Y eso es todavía un poco largo aliento. pero se siente un poco OO.

y oye cómo parece mejor hecho

namespace ABC 
{ 
    class POINT2{}; 
    class Complex:POINT2{}; 
    Complex ComplexFromPOINT2(POINT2 p){return new Complex();} 
    POINT2 POINT2FromComplex(Complex){return new POINT2();} 
} 

oye cómo se vería usos

int main() 
{ 
    ABC_Maths::Complex p = ABC_Maths_Conversion::ComplexFromPOINT2(new ABC_MATHS::POINT2()); 

    // or THE CLASS WAY 

    ABC.Maths.Complex p = ABC.Maths.Conversion.ComplexFromPOINT2(new ABC.Maths.POINT2()); 

    // or if in/using the ABC namespace 

    Maths.Complex p = Maths.Conversion.ComplexFromPOINT2(new Maths.POINT2()); 

    // and in the final case 

    ABC::Complex p = ABC::ComplexFromPOINT2(new ABC::POINT2()); 
} 

su sido interesante averiguar por qué nunca utilicé C++ espacios de nombres, como lo haría con C#. Sería demasiado largo, y nunca funcionaría de la misma manera que los espacios de nombres C#.

el mejor uso para los espacios de nombres en C++ es dejar de decir que mi función súper cout (que suena cada vez que se la llama) se confunde con la función std :: cout (que es mucho menos impresionante).

El hecho de que C# y C++ tengan espacios de nombres, no significa que el espacio de nombres signifique lo mismo. son diferentes pero similares. La idea de espacios de nombres C# debe provenir de espacios de nombres C++. alguien debe haber visto qué cosa similar pero diferente podría hacer, y no tenía suficiente poder de imaginación para darle su nombre original como "ClassPath", que tendría más sentido ya que es un camino hacia las clases en lugar de proporcionar nombrar espacios donde cada espacio puede tener los mismos nombres

espero que esto ayude a alguien

me olvidaba decir que todas estas formas son válidas, y el uso moderado de los dos primeros se pueden incorporar en el tercer a crear una biblioteca que tiene sentido decir (no gran ejemplo)

_INT::POINT2{} 

y

_DOUBLE::POINT2{} 

para que pueda cambiar el nivel de precisión mediante el uso de

#define PREC _DOUBLE 
// or #define PREC _INT 

y luego la creación de una instancia de PREC :: PUNTO2 de doble precisión PUNTO2

Eso no es una cosa fácil de hacer con C# o espacios de nombres de java

obviamente es solo un ejemplo.Piense en cómo se lee el uso.

Cuestiones relacionadas