una publicas protegidas programacion privadas orientada objetos miembros funciones codigo clases clase bases atributos c++

publicas - private y public en c++



¿Tiene influencia pública y privada en el diseño de memoria de un objeto? (2)

La respuesta depende de la versión del idioma, porque esto ha cambiado de C ++ 03 a C ++ 11.

En C ++ 03, la regla era:

Los miembros dentro del mismo bloque de control de acceso (es decir, de una de public palabras clave private , protected y private a la siguiente de ese conjunto) deben asignarse por orden de declaración dentro de la clase, no necesariamente de forma contigua.

En C ++ 11, la regla se cambió a esto:

Los miembros con el mismo nivel de control de acceso (público, protegido, privado) deben asignarse por orden de declaración dentro de la clase, no necesariamente de forma contigua.

Así que en C ++ 03, podrías garantizar esto (uso @ para indicar el desplazamiento de un miembro dentro de la clase):

  • @m_ac < @m_scp
  • @m_i1 < @m_i2 < @m_b1 < @m_b2

En C ++ 11, tienes algunas garantías más:

  • @m_ac < @m_scp
  • @m_sc < @m_i1 < @m_i2 < @m_b1 < @m_b2
  • @m_name < @m_b3

En ambas versiones, el compilador puede reordenar los miembros en diferentes cadenas según lo considere conveniente, e incluso puede intercalar las cadenas.

Tenga en cuenta que hay un mecanismo más que puede entrar en la imagen: clases de diseño estándar.

Una clase es de diseño estándar si no tiene elementos virtuales, si todos sus miembros de datos no estáticos tienen el mismo control de acceso, no tiene clases de base o miembros de datos no estáticos de tipo de diseño no estándar o tipo de referencia, y si tiene a lo sumo una clase con cualquier miembro de datos no estáticos en su cadena de herencia (es decir, no puede definir sus propios miembros de datos no estáticos y heredar algunos de una clase base).

Si una clase es de diseño estándar, existe una garantía adicional de que la dirección de su primer miembro de datos no estáticos es idéntica a la del objeto de clase en sí (lo que significa que el relleno no puede estar presente al principio del diseño de clase) .

Tenga en cuenta que las condiciones para ser de diseño estándar, junto con los compiladores prácticos que no hacen elecciones pesimistas, significan que en una clase de diseño estándar, los miembros se ordenarán de forma contigua en el orden de la declaración (con el relleno para la alineación intercalada según sea necesario).

Esta pregunta ya tiene una respuesta aquí:

Este es un seguimiento de otra pregunta mía: ¿Cuál es el orden óptimo de los miembros en una clase?

¿Cambia algo (excepto la visibilidad) si organizo a los miembros de manera tal que tomen turnos públicos, protegidos y privados?

class Example { public: SomeClass m_sc; protected: char m_ac[32]; SomeClass * m_scp; private: char * m_name; public: int m_i1; int m_i2; bool m_b1; bool m_b2; private: bool m_b3; };

¿Hay una diferencia entre esta clase y una clase en la que hago públicos a todos los miembros en tiempo de ejecución? Quiero seguir la regla de ordenar los tipos de grandes a pequeños (si la legibilidad no se ve seriamente perjudicada).

Supongo que no afecta en absoluto al programa compilado, al igual que const solo se verifica durante la compilación. ¿Es esto correcto?


Yo diría que la regla de ordenar no siempre es la mejor. Lo único que ganas haciendo es evitar el "relleno".

Sin embargo, otra "regla" a seguir es tener a los miembros más "calientes" en la parte superior para que puedan caber en una línea de caché, que normalmente es de 64 bytes.

Imagine que tiene un bucle que comprueba una bandera de su clase, y su desplazamiento es 1, y su otro miembro está en el desplazamiento 65, y otro en el desplazamiento 200. Obtendrá fallas en la memoria caché.

int count = 0; for (int i = 0; i < 10; i++) { if (class->flag/*offset:1*/ == true && class->flag2 == true/*offset:65*/) count += class->n; /*offset: 200*/ }

Ese bucle será mucho más lento que una versión para caché como:

int count = 0; for (int i = 0; i < 10; i++) { if (class->flag/*offset:1*/ == true && class->flag2 == true/*offset:2*/) count += class->n; /*offset: 3*/ }

El último bucle solo necesita leer una sola línea de caché por iteración. No puede ser más rápido.