resueltos resolucion programacion orientada operador objetos ejercicios ejemplos codigo clases ambito c++ inner-classes

resolucion - C++-¿Cuál es el punto de las clases anidadas?



operador de resolucion de ambito c++ (3)

Estoy estudiando un poco de C ++ y ahora estoy luchando contra sus similitudes con Java.

En primer lugar, tenga en cuenta que las clases anidadas de C ++ son similares a lo que en Java llama clases anidadas estáticas . No hay nada en la sintaxis de C ++ para reproducir clases anidadas de Java.

Descubro que los atributos privados de la clase "contenedor" no son visibles por la clase interna ...

C ++ 98

En C ++, las clases internas no son diferentes de las clases normales , no son miembros de la clase , entonces no pueden acceder a los miembros privados de la clase de contenedor (a diferencia de otros lenguajes como Java o C #).

C ++ 03

Las clases anidadas son miembros de la clase, pero las restricciones sobre lo que pueden acceder aún se aplican (vea también la sección Cosas extrañas al final de esta respuesta). Se ha considerado un defecto estándar (ver DR45 ), luego algunos compiladores implementaron anteriormente la regla de acceso C ++ 0x incluso cuando compilaban C ++ 03 (especialmente GCC, gracias a Jonathan Wakely para detectar esto).

C ++ 11

Esta regla cambió en C ++ 11, ahora las clases anidadas pueden acceder al miembro privado de la clase contenedora. De §11.7:

Una clase anidada es un miembro y, como tal, tiene los mismos derechos de acceso que cualquier otro miembro.

Por supuesto, todavía necesita una instancia para acceder a miembros no estáticos.

... entonces, ¿por qué debería usarlos?

Luego, son un detalle de implementación para agrupar clases relacionadas y tienen los mismos problemas sobre su uso que usted puede tener en otros idiomas (claridad para principiantes, principal). Su mayor beneficio IMO es la encapsulación, si por ejemplo tiene esto:

class stream { virtual void write(const std::string text) = 0; }; class channel { public: virtual stream* get_stream() = 0; // Other methods... }; class tcp_channel : public channel { public: virtual stream* get_stream() { return new tcp_stream(this); } private: class tcp_stream : public stream { /* implementation */ }; };

También son útiles en algunas circunstancias para sustituir espacios de nombres anidados:

class protocol { public: virtual void create_connection() = 0; class tcp : public protocol { /* implementation */ }; class shared_memory : public protocol { /* implementation */ }; class named_pipes: public protocol { /* implementation */ }; }; auto media = protocol::tcp();

O para ocultar los detalles de la implementación:

class file_system_entry { public: class file : public file_system_entry { }; class directory : public file_system_entry { }; std::time_t get_last_modified() { ... } void remove() { ... } virtual void copy_to(std::string path) = 0; private: class local_handle { // Implementation details } _handle; };

Hay muchos otros patrones de uso (vea también ¿Por qué uno usaría clases anidadas en C ++? Para una mejor discusión), solo recuerde que no todos los entenderán (y usarán) correctamente. Vea también ¿ Pros y contras de usar clases y enumeraciones de C ++ anidadas?

Además, ¿hay una manera de hacer visibles esos atributos?

Antes de C ++ 11 no puede (por supuesto, a menos que los declare como friend pero vea el siguiente párrafo), si necesita esta función, use un compilador de C ++ 11 (que admita esta función). GCC hace (desde hace mucho tiempo) y también MSVC, no sé acerca de otros compiladores.

Amigos anidados

¿Hay alguna diferencia entre las reglas de acceso de C ++ 11 y las clases de amigos? En general, son casi equivalentes ( el acceso automático es menos detallado):

class container { public: class nested; friend class nested; class nested { }; };

Comparado con:

class container { public: class nested { }; };

Sin embargo con la declaración hacia adelante tiene algunos efectos secundarios . También recuerde que desde el punto de vista de la accesibilidad son equivalentes (el acceso, como la amistad, no es hereditario ni transitivo). Estos ejemplos no se compilan:

class external : public container::nested { public: // No: only class declared inside "container" // has access to private members, we do not inherit that void foo(container obj) { /* access a private member of obj*/ } }; // No, "container" has not access to "nested" private members, // visibility isn''t reciprocal void container::foo(container::nested obj) { // Access some private member of obj } // No, we don''t have anything to do with container, // visibility isn''t transitive void friendOfNested(container obj) { // Access some private member of obj }

¿Entonces son completamente equivalentes ? No , porque los miembros privados de los amigos del container son accesibles en nested si es una clase anidada en C ++ 11, pero no lo son si nested es amigo de container . Dada esta estructura esbozada:

class container; class another { friend class container; }; class container { public: class nested { }; };

nested pueden acceder a los miembros privados de otros:

void container::nested::foo(another obj) { obj.somePrivateMember = 0; }

Funciona porque nested es un miembro del container , por lo que no se aplica la restricción transitiva de la amistad. Antes de C ++ 11, declarándose nested como amigo de container , ese código no se compilará porque la amistad no es transitiva.

Cosas raras

¿Asumiríamos que siempre podemos declarar una clase anidada como amiga de su contenedor? En realidad, dicho estándar (SO / IEC 14822: 2003 (E), 11.8):

Un amigo de una clase es una función o clase que no es miembro de la clase ...

Entonces no deberíamos poder declarar nested como amigo del container : en C ++ 03 las clases anidadas son miembros de la clase (pero el estándar dice explícitamente que no tienen acceso a los contenedores privados y tampoco pueden ser amigos de la clase del contenedor). Parece que no había esperanza, afortunadamente la mayoría de los compiladores nos permitieron hacerlo (independientemente de lo que dijera la norma).

Estoy estudiando un poco de C ++ y ahora estoy luchando contra sus similitudes con Java. Conozco el propósito de las clases internas en Java, pero ahora estoy tratando de usar clases anidadas en C ++, y descubro que los atributos privados de la clase "contenedor" no son visibles por clase anidada , ¿por qué debo usarlos? Además, ¿hay alguna manera de hacer visibles esos atributos?


Diferente no es lo mismo.

Las clases internas de Java crean objetos que se supone que están conectados con un objeto de la clase externa , por lo que el acceso a los miembros de la clase externa desde los métodos de la clase interna se puede realizar sin crear explícitamente un puntero o una referencia. C ++ no hace eso; una clase anidada es solo una clase cuya definición está anidada dentro de la definición de otra clase. Eso es útil para la encapsulación, pero eso es todo: no tiene la intención de hacer que objetos mágicos de ese tipo conozcan objetos del tipo que contiene.


Proporciona otra buena técnica de encapsulación. Colocar una clase completamente dentro del espacio de nombres de otra clase reduce su visibilidad a otras partes de su base de código. Esto ayuda a lograr escalabilidad y reduce su carga de mantenimiento.

Los objetos de función a menudo se codifican de esa manera.