¿Cuáles son los pros y los contras de la utilización de anidado pública de clases de C++ y las enumeraciones? Por ejemplo, supongamos que tenemos una clase llamada printer, y esta clase también se almacena la información en la bandeja de salida, usted podría tener:

class printer
{
public:
    std::string name_;

    enum TYPE
    {
        TYPE_LOCAL,
        TYPE_NETWORK,
    };

    class output_tray
    {
        ...
    };
    ...
};

printer prn;
printer::TYPE type;
printer::output_tray tray;

Alternativamente:

class printer
{
public:
    std::string name_;
    ...
};

enum PRINTER_TYPE
{
    PRINTER_TYPE_LOCAL,
    PRINTER_TYPE_NETWORK,
};

class output_tray
{
    ...
};

printer prn;
PRINTER_TYPE type;
output_tray tray;

Puedo ver los beneficios de anidación privado enumeraciones/clases, pero cuando se trata de los públicos, la oficina está dividida parece ser más de una opción de estilo.

Así que, ¿qué prefieren y por qué?

InformationsquelleAutor Rob | 2008-10-19

13 Comentarios

  1. 44

    Clases anidadas

    Hay varios efectos secundarios a clases anidadas dentro de las clases que me suele considerar la posibilidad de fallas (si no puro antipatrones).

    Imaginemos el siguiente código :

    class A
    {
       public :
          class B { /* etc. */ } ;
    
       //etc.
    } ;

    O incluso:

    class A
    {
       public :
          class B ;
    
       //etc.
    } ;
    
    class A::B
    {
       public :
    
       //etc.
    } ;

    Así:

    • Privilegied de Acceso: a::B tiene privilegied acceso a todos los miembros de Un (métodos, variables, símbolos, etc.), lo que debilita la encapsulación
    • a su ámbito de aplicación es candidato para la búsqueda de símbolos: de código desde el interior de B va a ver todos símbolos de Una como posibles candidatos para un símbolo de búsqueda, lo cual puede confundir el código
    • siguiente declaración: no Hay manera de declarar A::B, sin dar una declaración completa de Un
    • Extensibilidad: es imposible añadir otra clase a::C, a menos que usted es propietario de Un
    • Código de verbosidad: poniendo clases en clases sólo hace que los encabezados de los más grandes. Todavía se puede separar esta en varias declaraciones, pero no hay manera de utilizar el espacio de nombres como alias, las importaciones o los utilizan.

    Como conclusión, salvo excepciones (por ejemplo, la clase anidada es una parte íntima de la anidación de la clase… Y aún así…), no veo el punto de clases anidadas en condiciones normales de código, como las fallas outweights por las magnitudes de las ventajas percibidas.

    Además, huele como un torpe intento de simular namespacing sin el uso de C++ espacios de nombres.

    En el pro-lado, aislar este código, y si es privada, lo hacen inutilizable, pero desde el «exterior» de la clase…

    Anidada las enumeraciones

    Pros: Todo.

    Con: Nada.

    El hecho es que la enumeración de elementos va a contaminar el ámbito global:

    //collision
    enum Value { empty = 7, undefined, defined } ;
    enum Glass { empty = 42, half, full } ;
    
    //empty is from Value or Glass?

    Ony poniendo cada enum en un espacio de nombres diferente/clase le permitirá evitar esta colisión:

    namespace Value { enum type { empty = 7, undefined, defined } ; }
    namespace Glass { enum type { empty = 42, half, full } ; }
    
    //Value::type e = Value::empty ;
    //Glass::type f = Glass::empty ;

    Tenga en cuenta que C++0x define la clase enum:

    enum class Value { empty, undefined, defined } ;
    enum class Glass { empty, half, full } ;
    
    //Value e = Value::empty ;
    //Glass f = Glass::empty ;

    exactamente para este tipo de problemas.

    • Buen ejemplo de una instrucción anidada privado de la clase es la de los enlaces en la lista dentro de un std::list. No hay ninguna necesidad de que nadie sepa acerca de ellos, usar o interactuar con ellos (¿o es que aún existe realmente 😉
    • Yo uso un anidada clase privada cada ahora y entonces, por la pImpl-patrón.
    • El anidado de clase privada en la PImpl patrón significa que el usuario va a ver la implementación de la clase, incluso si no es accesible. Tener una simple declaración forward sólo declarar el nombre, y nada más. Usted será capaz de definir completamente la aplicación en otros lugares (oculto para el usuario)… ^_^ ..
    • La declaración forward problema es más que un inconveniente. Usted puede obtener usted mismo atrapado en un lazo de dependencia que requiere de la onu-de anidación de la zona del problema. La onu-de anidación podría, a continuación, crear el diseño de la inconsistencia, o tendría que cambiar toda tu proyecto de onu-anidada : / stackoverflow.com/questions/951234/…
    • Estás en lo correcto acerca de la declaración. +1
    • He completado las «clases anidadas» de la sección después de la investigación adicional (impulsado por una discusión técnica con un amigo). Los resultados son los mismos (salvo excepciones, las clases anidadas NO son Bien), pero las razones son mejor detallados.

  2. 6

    Una estafa que puede convertirse en un gran negocio para los grandes proyectos es que es imposible hacer una declaración forward para las clases anidadas o enumeraciones.

    • Tenga en cuenta que el uso de un espacio de nombres para anidar una clase de habilitar al usuario a reenviar a declarar esta clase: es decir: <code>espacio de nombres Foo { clase de Bar ; }</código de>. De todos modos, +1 por el comentario.
  3. 2

    Si usted nunca va a ser el uso de la clase dependiente para cualquier cosa, pero trabajar con el independiente de la clase de las implementaciones, las clases anidadas están bien, en mi opinión.

    Es cuando quieres ser el uso de la «interna» de la clase como un objeto en su propio derecho, de que las cosas pueden empezar a tener un poco de manky y tienes que empezar a escribir de extracción/inserción de las rutinas. No es una bonita situación.

  4. 2

    Parece que debe ser el uso de espacios de nombres en lugar de clases de grupo como las cosas que están relacionados unos con otros de esta manera. Una estafa que pude ver en el hacer de las clases anidadas es que usted termina con un gran archivo de origen que podría ser difícil de asimilar cuando usted está buscando para una sección.

  5. 2

    No hay pros y los contras de por sí de utilizar anidada pública de clases de C++. Sólo hay hechos. Esos hechos son los exigidos por el estándar de C++. Si un hecho acerca de anidado pública de clases de C++ es un profesional o un estafador depende del problema concreto que se está tratando de resolver. El ejemplo que han dado no permite un juicio acerca de si las clases anidadas son adecuadas o no.

    Un hecho sobre las clases anidadas es, que tienen acceso privilegiado a todos los miembros de la clase a la que pertenecen. Esto es una estafa, si las clases anidadas no necesita este tipo de acceso. Pero si la clase anidada no necesita este tipo de acceso, entonces no debería haber sido declarada como una clase anidada. Hay situaciones, cuando una clase Un desea conceder acceso privilegiado a ciertas clases de B. Hay tres soluciones a este problema

    1. Hacer B un amigo de Un
    2. Hacer B una clase anidada de Un
    3. Hacer que los métodos y atributos, que B necesidades, los miembros públicos de Un.

    En esta situación, es #3 que viole la encapsulación, porque Un tiene control sobre sus amigos y sobre sus clases anidadas, pero no de las clases que llamar a sus métodos públicos o de acceso público de los atributos.

    Otro hecho acerca de las clases anidadas es, que es imposible añadir otra clase A::C como una clase anidada de Un a menos que usted es dueño de Un. Sin embargo, esto es perfectamente razonable, porque las clases anidadas tienen un acceso privilegiado. Si fuera posible añadir A::C como una clase anidada de Un, entonces A::C podría engañar Un en la concesión de acceso a información privilegiada; y que yould violar la encapsulación. Es básicamente el mismo que el de la friend declaración: el friend declaración no le concede ningún privilegio especial, que su amigo se esconde de los demás, es lo que permite a tus amigos a acceder a la información que se esconden de su no-amigos. En C++, llamar a alguien un amigo es un acto altruista, no es un egoísta uno. Lo mismo vale para permitir que una clase sea una clase anidada.

    Som otros hechos acerca de anidado clases públicas:

    • Un ámbito es candidato para la búsqueda de símbolos de B: Si usted no quiere esto, hacer B un amigo de Un en lugar de una clase anidada. Sin embargo, hay casos en los que desea exactamente este tipo de búsqueda de símbolos.
    • A::B no puede ser hacia adelante-declaró: Un y a::B están estrechamente acoplados. Ser capaz de utilizar a::B sin saber Un sería sólo de ocultar este hecho.

    Resumir de esta manera: si la herramienta no se ajuste a sus necesidades, no culpes a la herramienta; culparse a sí mismo por el uso de la herramienta; otros pueden tener diferentes problemas, para que la herramienta es perfecta.

  6. 1

    paercebal dijo todo lo que yo diría sobre anidada de las enumeraciones.

    WRT clases anidadas, mi comunes y casi único caso de uso para ellos es cuando tengo una clase que es la manipulación de un tipo específico de recurso, y necesito una clase de datos que representa algo específico para ese recurso. En su caso, output_tray podría ser un buen ejemplo, pero no creo que en general el uso de las clases anidadas si la clase va a tener cualquiera de los métodos que van a ser llamada desde fuera de la clase que las contiene, o es más de lo que principalmente una clase de datos. Yo generalmente no nido clases de datos, a menos que el contenido de la clase es que no siempre se hace referencia directamente fuera de la clase que las contiene.

    Así, por ejemplo, si yo tuviera un printer_manipulator clase, puede tener un contenido de clase de la impresora errores de manipulación, pero la impresora en sí sería una no-clase que contiene.

    Espero que esto ayude. 🙂

  7. 1

    Recuerde que siempre puede promover una clase anidada a un nivel superior de una tarde, pero usted no puede ser capaz de hacer lo contrario sin romper el código existente. Por lo tanto, mi consejo sería hacer una clase anidada en primer lugar, y si comienza a convertirse en un problema, hacer una clase de nivel superior en la próxima versión.

  8. 0

    Para mí una gran estafa a tener fuera de ella es que se convierte en parte del espacio de nombres global. Si la enumeración o relacionados con la clase sólo se aplica realmente a la clase que está en, entonces tiene sentido. Así, en el caso de impresora, todo lo que incluye la impresora se sabe acerca de tener acceso completo a la enumeración PRINTER_TYPE, donde realmente no necesita saber acerca de él. Yo no puedo decir que alguna vez ha utilizado una clase interna, pero para una enumeración, esto parece más lógico mantenerlo dentro. Como otro cartel ha señalado, es también una buena idea para utilizar espacios de nombres para el grupo de artículos similares, ya que la obstrucción del espacio de nombres global puede ser realmente una mala cosa. Anteriormente he trabajado en proyectos que son enormes y sólo traer un auto de la lista completa en el espacio de nombres global, que tarda 20 minutos. En mi opinión anidada de las enumeraciones y los nombres de espacios de clases/estructuras son, probablemente, el más limpio de enfoque.

  9. 0

    Estoy de acuerdo con los posts de abogar por la incrustación de enum en una clase, pero hay casos en los que tiene más sentido para no hacerlo (pero por favor, al menos ponerlo en un espacio de nombres). Si varias clases de la utilización de un enum definidos dentro de una clase diferente, a continuación, las clases son directamente dependientes de esa otra clase concreta (que es propietaria de la enumeración). Que sin duda representa un defecto de diseño, ya que la clase será el responsable de que enum así como otras responsabilidades.

    Así que, sí, incrustar la enumeración en una clase si otro código que sólo utiliza esa enumeración de interfaz directamente con esa clase concreta. De lo contrario, encontrar un lugar mejor para mantener la enumeración como un espacio de nombres.

  10. 0

    Si pones la enumeración en una clase o de un espacio de nombres, intellisense será capaz de darle la orientación cuando usted está tratando de recordar la enumeración de los nombres. Una pequeña cosa, pero a veces las cosas pequeñas de la materia.

  11. 0

    Visual Studio 2008 no parecen ser capaces de proporcionar intellisense para las clases anidadas, así que me he cambiado a la PIMPL lenguaje en la mayoría de los casos, donde yo solía tener una clase anidada. Siempre pongo las enumeraciones, ya sea en la clase, si es utilizado sólo por esa clase, o fuera de la clase en el mismo espacio de nombres como los de clase cuando más de una clase se utiliza la enumeración.

  12. 0

    Puedo ver un punto en contra para las clases anidadas, que uno puede utilizar mejor la programación genérica.

    Si la pequeña clase se define fuera de la gran uno, usted puede hacer la gran clase de una plantilla de clase y el uso de cualquier «pequeño» de la clase que usted puede necesitar en el futuro con la gran clase.

    De programación genérica es una herramienta poderosa, y, en mi humilde opinión, debemos tener en cuenta a la hora de desarrollar extensible programas. Extraño, que nadie ha mencionado este punto.

  13. -1

    Único problema con clases anidadas que me chocó fue que C++ no hagamos referencia a los objetos de la clase envolvente, en la clase anidada funciones. No podemos decir «Adjuntando::este»

    (Pero tal vez hay una forma?)

    • Hay una confusión aquí. clase Anidada no implica que objeto anidado. Para un objeto b de tipo a::B, no puede ser un objeto de tipo Un, que b es un miembro de. Si usted quiere una relación, usted tiene que crear uno usted mismo.
    • Tienes razón, puede que no. Pero muchas veces hay. Este modismo es común
    • Tienes razón, puede que no. Pero muchas veces hay. Este modismo es común: class a { int m; class B { int getM(); } B b; } donde B objetos son siempre componentes de un real de Un objeto. Si C++ agregar un «padre», como ella misma ha «esto» podría implementar getM así: int a::B::getM() { return padre->m; } (Esto es meramente académico.)

Dejar respuesta

Please enter your comment!
Please enter your name here