que - libreria para enum c++
¿Ventajas y desventajas de usar clases anidadas de C++ y enumeraciones? (13)
Clases anidadas
Hay varios efectos secundarios en las clases anidadas dentro de las clases que generalmente considero defectos (si no antipatrones puros).
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.
} ;
Asi que:
- Acceso privilegiado: A :: B tiene acceso privilegiado a todos los miembros de A (métodos, variables, símbolos, etc.), lo que debilita la encapsulación.
- El alcance de A es candidato para la búsqueda de símbolos: el código del interior B verá todos los símbolos de A como posibles candidatos para la búsqueda de símbolos, lo que puede confundir el código
- forward-declaration: no hay forma de reenviar-declarar A :: B sin dar una declaración completa de A
- Extensibilidad: es imposible agregar otra clase A :: C a menos que sea propietario de A
- Verbosidad del código: poner clases en clases solo hace que los encabezados sean más grandes. Aún puede separar esto en varias declaraciones, pero no hay forma de usar alias, importaciones o usos similares a los del espacio de nombres.
Como conclusión, a menos que las excepciones (por ejemplo, la clase anidada sea una parte íntima de la clase de anidación ... E incluso entonces ...), no veo sentido en las clases anidadas en el código normal, ya que las fallas pesan más que las ventajas percibidas .
Además, huele como un torpe intento de simular el espacio de nombres sin usar espacios de nombres C ++.
En el lado favorable, usted aísla este código, y si es privado, hágalo inutilizable pero de la clase "externa" ...
Enums anidados
Pros: todo.
Con: Nada.
El hecho es que los artículos enum contaminarán el alcance global:
// collision
enum Value { empty = 7, undefined, defined } ;
enum Glass { empty = 42, half, full } ;
// empty is from Value or Glass?
Ony al poner cada enumeración en un espacio de nombres / clase diferente 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 definió 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.
¿Cuáles son los pros y los contras de usar clases y enumeraciones públicas C ++ anidadas? Por ejemplo, supongamos que tiene una clase llamada printer
, y esta clase también almacena información en bandejas de salida, 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 anidar enums / classes privados, pero cuando se trata de públicos, la oficina está dividida, parece ser más una elección de estilo.
Entonces, ¿qué prefieres y por qué?
El único problema con las clases anidadas con las que me topé todavía fue que C ++ no nos permite referirnos al objeto de la clase adjunta, en las funciones de clase anidadas. No podemos decir "Enclosing :: this"
(Pero tal vez hay una manera?)
Estoy de acuerdo con las publicaciones que defienden la inclusión de su enumeración en una clase, pero hay casos en los que tiene más sentido no hacerlo (pero, por favor, al menos póngalo en un espacio de nombres). Si varias clases están utilizando una enumeración definida dentro de una clase diferente, esas clases dependen directamente de esa otra clase concreta (que posee la enumeración). Eso seguramente representa un defecto de diseño ya que esa clase será responsable de esa enumeración así como de otras responsabilidades.
Entonces, sí, incrusta la enumeración en una clase si el otro código solo usa esa enumeración para interactuar directamente con esa clase concreta. De lo contrario, encuentre un lugar mejor para mantener la enumeración, como un espacio de nombres.
No existen pros y contras per se de usar clases C ++ públicas anidadas. Solo hay hechos Esos hechos son obligatorios según el estándar de C ++. Si un hecho sobre las clases de C ++ público anidado es un pro o un contra depende del problema particular que está tratando de resolver. El ejemplo que ha proporcionado no permite un juicio sobre si las clases anidadas son apropiadas 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 necesitan dicho acceso. Pero si la clase anidada no necesita dicho acceso, entonces no debería haber sido declarada como una clase anidada. Hay situaciones en que una clase A quiere otorgar acceso privilegiado a otras clases B. Hay tres soluciones para este problema
- Haz que B sea amigo de A
- Haga de B una clase anidada de A
- Haga los métodos y atributos, que B necesita, miembros públicos de A.
En esta situación, es # 3 que viola la encapsulación, porque A tiene control sobre sus amigos y sobre sus clases anidadas, pero no sobre las clases que llaman a sus métodos públicos o tienen acceso a sus atributos públicos.
Otro hecho sobre las clases anidadas es que es imposible agregar otra clase A :: C como una clase anidada de A a menos que usted sea el propietario de A. Sin embargo, esto es perfectamente razonable, porque las clases anidadas tienen acceso privilegiado. Si fuera posible agregar A :: C como una clase anidada de A , entonces A :: C podría engañar a A para que otorgue acceso a información privilegiada; y que violaría la encapsulación. Es básicamente lo mismo que con la declaración de friend
: la declaración de friend
no le otorga ningún privilegio especial, que su amigo se esconde de los demás; permite a tus amigos acceder a la información que estás ocultando a tus no amigos. En C ++, llamar a alguien amigo es un acto altruista, no egoísta. Lo mismo vale para permitir que una clase sea una clase anidada.
Som otros hechos sobre clases públicas anidadas:
- El alcance de A es candidato para la búsqueda de símbolos de B : si no quieres esto, haz de B un amigo de A 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 se puede declarar hacia adelante: A y A :: B están estrechamente relacionados. Ser capaz de usar A :: B sin saber A solo escondería este hecho.
Para resumir esto: si la herramienta no se ajusta a sus necesidades, no culpe a la herramienta; culparte a ti mismo por usar la herramienta; otros pueden tener problemas diferentes, para los cuales la herramienta es perfecta.
Para mí, una gran estafa al tenerlo afuera es que se convierte en parte del espacio de nombres global. Si la enumeración o la clase relacionada solo se aplica realmente a la clase en la que se encuentra, entonces tiene sentido. Entonces, en el caso de la impresora, todo lo que incluye la impresora sabrá si tiene acceso completo a la ENUM PRINTER_TYPE, donde realmente no necesita saber al respecto. No puedo decir que alguna vez haya usado una clase interna, pero para una enumeración, parece más lógico mantenerla dentro. Como ha señalado otro afiche, también es una buena idea usar espacios de nombres para agrupar elementos similares, ya que obstruir el espacio de nombres global realmente puede ser algo malo. Anteriormente trabajé en proyectos que son masivos y solo mencionar una lista de autocompletar en el espacio de nombres global lleva 20 minutos. En mi opinión, las enumeraciones anidadas y las clases / estructuras con espacios de nombres son probablemente el enfoque más limpio.
Parece que debería usar espacios de nombres en lugar de clases para agrupar cosas similares que están relacionadas entre sí de esta manera. Una estafa que pude ver al hacer clases anidadas es que terminas con un archivo fuente realmente grande que podría ser difícil de asimilar cuando estás buscando una sección.
Puedo ver una estafa para las clases anidadas, que uno puede usar mejor la programación genérica.
Si la pequeña clase se define fuera de la grande, puede hacer que la clase grande sea una plantilla de clase y usar cualquier clase "pequeña" que pueda necesitar en el futuro con la clase grande.
La programación genérica es una herramienta poderosa y, en mi humilde opinión, debemos tenerla en cuenta al desarrollar programas extensibles. Extraño, que nadie ha mencionado este punto.
Recuerde que siempre puede promover una clase anidada a una de nivel superior más adelante, pero es posible que no pueda hacer lo contrario sin romper el código existente. Por lo tanto, mi consejo sería convertirlo en una clase anidada primero, y si comienza a convertirse en un problema, conviértalo en una clase de nivel superior en la próxima versión.
Si nunca vas a utilizar la clase dependiente para nada más que para trabajar con las implementaciones de la clase independiente, las clases anidadas están bien, en mi opinión.
Es cuando quieres usar la clase "interna" como un objeto en sí mismo, las cosas pueden empezar a ser un poco maniquíes y tienes que empezar a escribir rutinas de extractor / insertador. No es una situación bonita.
Si pones la enumeración en una clase o un espacio de nombres, intellisense podrá guiarte cuando intentes recordar los nombres enum. Algo pequeño seguro, pero a veces las cosas pequeñas importan.
Una desventaja que puede convertirse en un gran problema para los proyectos grandes es que es imposible hacer una declaración directa para las clases o enumeraciones anidadas.
Visual Studio 2008 no parece ser capaz de proporcionar intellisense para las clases anidadas, por lo que he cambiado al idioma PIMPL en la mayoría de los casos donde solía tener una clase anidada. Siempre pongo enumeraciones en la clase si solo las usa esa clase, o fuera de la clase en el mismo espacio de nombres de la clase cuando más de una clase usa la enumeración.
paercebal dijo todo lo que diría sobre las enumeraciones anidadas.
Clases anidadas WRT, mi caso de uso común y casi único para ellos es cuando tengo una clase que está manipulando un tipo específico de recurso, y necesito una clase de datos que represente algo específico para ese recurso. En su caso, output_tray podría ser un buen ejemplo, pero generalmente no uso clases anidadas si la clase va a tener algún método que vaya a ser llamado desde fuera de la clase contenedora, o es más que una clase de datos. Generalmente, no anido las clases de datos a menos que la clase contenida no se referencia directamente fuera de la clase contenedora.
Entonces, por ejemplo, si tuviera una clase printer_manipulator, podría tener una clase contenida para errores de manipulación de la impresora, pero la impresora misma sería una clase no contenida.
Espero que esto ayude. :)