Espacios de nombres
Variantes
Acciones

Objetos

De cppreference.com
< cpp‎ | language

Los programas de C++ crean, destruyen, referencian , acceden y manipulan objetos.

Un objeto, en C++, es una zona de almacenamiento que tiene

Las siguientes entidades no son objetos: valor, referencia, función, enumerado, tipo, miembro no estático de clase, campo de bits, plantilla, plantilla especializada de clase o función, espacio de nombres, paquete de parámetros y this.

Una variable es un objeto o referencia que no es un miembro no estático de datos, que es presentado mediante una declaración.

Los objetos son creados mediante definiciones, expresiones new, expresiones throw, cuando cambia el miembro activo de una unión, y cuando se requieren objetos temporales.

Contenido

[editar] Representación de objeto y de valor

Para un objeto de tipo T, la representación de objeto es la secuencia de sizeof(T) objetos de tipo unsigned char (o el equivalente: std::byte) comenzando en la misma dirección que el objeto T.

La representación de valor de un objeto es el conjunto de bits que mantienen el valor del tipo T

Para los tipos TriviallyCopyable, la representación del valor es una parte de la representación del objeto, lo que significa que copiar los bytes ocupados por el objeto en el almacenamiento es suficiente para producir otro objeto con el mismo valor (excepto si el valor es una representación errónea de su tipo y al cargarlo en la CPU genera una excepción de hardware, como valores SNaN (señalización de no número) de coma flotante o enteros NaT (no una cosa)).

Lo contrario no es necesariamente verdadero: dos objetos de tipo TriviallyCopyable con distinta representación de objeto pueden representar el mismo valor. Por ejemplo, varios patrones de bits en coma flotante representan el mismo valor especial NaN. Más común, algunos bits de la representación del objeto no participan en la representación del valor; como los bits que se insertan para satisfacer los requisitos de alineación, tamaños de campos de bits, etc.

#include <cassert>
struct S {
    char c;  // valor de 1 byte 
             // 3 bytes de relleno
    float f; // valor de 4 bytes (suponiendo sizeof(float) == 4)
    bool operator==(const S& arg) const { // igualdad basada en el valor
        return c == arg.c && f == arg.f;
    }
};
assert(sizeof(S) == 8);
S s1 = {'a', 3.14};
S s2 = s1;
reinterpret_cast<char*>(&s1)[2] = 'b'; // modifica el segundo byte
assert(s1 == s2); // el valor no cambia


Para objetos de tipo char, signed char, and unsigned char (a menos que sean campos de bits de gran tamaño), se requiere que cada bit de la representación del objeto participe en la representación del valor y cada posible patrón de bits representa un valor distinto (no se permite relleno, trap bits o representación múltiple).

[editar] Subobjetos

Un objeto puede contener otros objetos, que se denominan subobjetos. Esto incluye

  • objetos miembro
  • subobjetos de la clase base
  • matriz de elementos

Un objeto que no es subobjeto de otro se denomina objeto completo.

A los objetos completos, objetos miembro y matrices de elementos también se les conoce como objetos más derivados, para distinguirlos de los subobjetos de clase base. El tamaño de un objeto más derivado que no es un campo de bits y no está marcado [[no dirección única]] (desde C++20) es necesariamente distinto de cero (el tamaño de un subobjeto de clase base puede ser cero incluso sin [[no dirección única]] (desde C++20): ver optimización de base vacía).

Se garantiza que dos objetos con tiempos de vida superpuesto (que no son campos de bits) tienen direcciones diferentes a menos que uno de ellos sea un subobjeto del otro o proporcione almacenamiento para el otro, o si son subobjetos de diferente tipo dentro del mismo objeto completo, y uno de ellos es una base de tamaño cero.

static const char c1 = 'x';
static const char c2 = 'x';
assert(&c1 != &c2); // mismo valor, diferentes direcciones

[editar] Objetos polimorfos

Los objetos de un tipo de clase que declara o hereda al menos una función virtual son objetos polimorfos. Dentro de cada objeto polimorfo, la implementación almacena información adicional (en cada implementación existente, es un puntero a menos que esté optimizado), que es utilizada para llamadas a función virtual y por las características de RTTI (cast dinámico y id de tipo) para determinar, en tiempo de ejecución, el tipo con el que se creó el objeto, independientemente de la expresión en la que se use.

Para objetos no polimorfos, la interpretación del valor es determinada según la expresión en que se use, y se determina en tiempo de compilación.

#include <iostream>
#include <typeinfo>
struct Base1 {
    // tipo polimorfo: declara un miembro virtual
    virtual ~Base1() {}
};
struct Derived1 : Base1 {
     // tipo polimorfo: hereda un miembro virtual
};
 
struct Base2 {
     // tipo no polimorfo
};
struct Derived2 : Base2 {
     // tipo no polimorfo
};
 
int main()
{
    Derived1 obj1; // obj1 se crea del tipo  Derived1
    Derived2 obj2; // obj2 se crea el tipo Derived2
 
    Base1& b1 = obj1; // b1 referencia al objeto obj1
    Base2& b2 = obj2; // b2 referencia al objeto obj2
 
    std::cout << "Tipo de expresión de b1: " << typeid(decltype(b1)).name() << ' '
              << "Tipo de expresión de b2: " << typeid(decltype(b2)).name() << '\n'
              << "Tipo de objeto de b1: " << typeid(b1).name() << ' '
              << "Tipo de objeto de b2: " << typeid(b2).name() << '\n'
              << "tamaño de b1: " << sizeof b1 << ' '
              << "tamaño de b2: " << sizeof b2 << '\n';
}

Salida:

Tipo de expresión de b1: Base1 Tipo de expresión de b2: Base2
Tipo de objeto de b1: Derived1 Tipo de objeto b2: Base2
tamaño de b1: 8 tamaño de b2: 1

[editar] Alias estricto

El acceso a un objeto usando una expresión de otro tipo distinto al tipo con el que fue creado, en muchos casos tiene un comportamiento indeterminado, ver reinterpret_cast para la lista de excepciones y ejemplos.

[editar] Alineamiento

Cada tipo de objeto tiene la propiedad requisitos de alineamiento, que es un valor entero ( de tipo std::size_t, siempre potencia de 2) que representa el número de bytes entre direcciones sucesivas donde se pueden alojar objetos de este tipo. El requisito de alineamiento de un tipo se puede obtener mediante alignof o std::alignment_of. La función de alineamiento de puntero std::align se puede utilizar para obtener un puntero adecuadamente alineado dentro de cualquier buffer, y std::aligned_storage se puede usar para obtener un almacenamiento alineado adecuadamente.

Cada tipo de objeto impone su requisito de alineamiento en cada objeto de este tipo; se puede indicar una alineación más estricta (con mayor requisito de alineación) usando alignas.

Para satisfacer los requisitos de alineamiento de todos los miembros no estáticos de una clase, se puede insertar relleno después de algunos de sus miembros.

#include <iostream>
 
// los objetos de tipo S se pueden alojar en cualquier dirección
// porque S.a y S.b pueden ser alojados en cualquier dirección
struct S {
  char a; // tamaño: 1, alineación: 1
  char b; // tamaño: 1, alineación: 1
}; // tamaño: 2, alineación: 1
 
// Los objetos de tipo X se deben alojar en bloques de 4 bytes
// porque X.n se debe alojar en bloques de 4 bytes
// porque el requisito de alineamiento de int es (normalmente) 4
struct X {
  int n;  // tamaño: 4, alineación: 4
  char c; // tamaño: 1, alineación: 1
  // tres bytes de relleno
}; // tamaño: 8, alineación: 4 
 
int main()
{
    std::cout << "sizeof(S) = " << sizeof(S)
              << " alignof(S) = " << alignof(S) << '\n';
    std::cout << "sizeof(X) = " << sizeof(X)
              << " alignof(X) = " << alignof(X) << '\n';
}

Salida:

sizeof(S) = 2 alignof(S) = 1
sizeof(X) = 8 alignof(X) = 4


La alineación más tenue (el requisito de alineamiento menor) es la alineación de char, signed char, y unsigned char, que es igual a 1; la alineación fundamental más grande de cualquier tipo es la alineación de std::max_align_t. Si la alineación de un tipo se hace más estricta (más grande) que std::max_align_t usando alignas, se conoce como un tipo con requisito de alineamiento extendido. Un tipo cuya alineación es extendida o un tipo de clase cuyo miembro de datos no estático tiene una alineación extendida es un "tipo sobrealineado". Está definido en la implementación si la expresión new, std::allocator::allocate, y std::get_temporary_buffer admiten tipos sobrealineados. A los asignadores instanciados con tipos sobrealineados se les permite fallar en la instancia en tiempo de compilación, para lanzar std::bad_alloc en tiempo de ejecución, para ignorar los requisitos de alineamiento no soportados, o para manejarlos correctamente.

[editar] Ver también

Documentacion C de objeto