Siempre me he preguntado este tipo de cosas, así que decidí dar una respuesta completa. Se trata de lo que cabría esperar, y es predecible (yay)! Por lo tanto, con la información a continuación, debe ser capaz de predecir el tamaño de una clase.
Uso de Visual Studio Community 2017 (Version 15.2), en modo de lanzamiento, con todas las optimizaciones discapacitado y RTTI (Run-time Type Information) fuera, que han determinado lo siguiente:
respuesta era corto:
En primer lugar:
- En el bit 32 (x86),
<size of pointer> == 4
bytes
- En el bit 64 (x64),
<size of pointer> == 8
bytes
- Cuando digo "la herencia de clases virtual", es decir por ejemplo:
class ChildClass: virtual public ParentClass
Ahora, mis conclusiones son que:
- clases vacías son 1 byte
- herencia de una clase vacía es aún 1 byte
- clases vacías con funciones todavía de 1 byte (?! ver Nota explicación a continuación)
- herencia de una clase vacía con una función sigue siendo 1 byte
- añadir una variable a una clase vacía se
<size of variable>
bytes
- heredar una clase con una variable y añadiendo otra variable es
<size of variables>
bytes
- que heredan una clase y imperiosas su función añade un vtable (explicación adicional proporcionada en Conclusiones sección) y
<size of pointer>
bytes
- simplemente declarando una virtua función l también añade un vtable, por lo que es
<size of pointer>
bytes
- herencia de clases virtual de una clase vacía (con o sin una función miembro) también añade un vtable, y hace que la clase
<size of pointer>
bytes
- herencia de clases virtual de un no vacía clase también añade un vtable, pero se hace un poco complicado: se añade
<size of pointer>
bytes al total, envolviendo todas las variables miembro en tantos incrementos <size of pointer>
bytes como sea necesario para cubrir <total size of member variables>
- sí, has leído bien. .. (ver mi conjetura sobre lo que está pasando en Conclusiones ...)
Nota que incluso intenté que la función() incluyera texto, creara una instancia de la clase y llamara a la función; no cambia el tamaño de la clase de función (¡no es una optimización)! Me sorprendió un poco, pero en realidad tiene sentido: las funciones de los miembros no cambian, por lo que se pueden almacenar de forma externa a la clase misma.
Conclusiones:
- clases vacías son de 1 byte, ya que es el mínimo requerido para que tenga una presencia en la memoria. Sin embargo, una vez que se agregan los datos de datos o vtable, comience a contar a 0 bytes.
- Agregar una función miembro (no virtual) no hace nada al tamaño, porque la función miembro se almacena externamente.
- Declarar que una función miembro es virtual (¡incluso si la clase no está anulada!) O anular una función miembro en una clase secundaria agrega lo que se llama "vtable" or "virtual function table", que permite Dynamic Dispatch (que es realmente genial de usar y Recomiendo usarlo). Este vtable consume
<size of pointer>
bytes, agregando <size of pointer>
bytes a dicha clase. Este vtable solo puede existir una vez por clase (ya sea que lo haga o no), por supuesto.
- Agregar una variable miembro aumenta el tamaño de la clase por esa variable miembro, independientemente de si dicha variable miembro está en la clase principal o secundaria (aunque la clase principal sigue siendo de su propio tamaño, por supuesto).
- La herencia de clase virtual es la única parte que se complica ... Entonces ... Creo que lo que sucede después de un poco de experimentación es: el tamaño de la clase en realidad aumenta en
<size of pointer>
bytes a la vez, incluso si no lo hace t necesidad de consumir esta cantidad de memoria, supongo que porque es la adición de un "bloque ayudante" vtable para cada <size of pointer>
bytes de memoria o algo ...
respuesta larga:
Decidí todo esto usando este código:
#include <iostream>
using namespace std;
class TestA
{
};
class TestB: public TestA
{
};
class TestC: virtual public TestA
{
};
class TestD
{
public:
int i;
};
class TestE: public TestD
{
public:
int j;
};
class TestF: virtual public TestD
{
public:
int j;
};
class TestG
{
public:
void function()
{
}
};
class TestH: public TestG
{
public:
void function()
{
}
};
class TestI: virtual public TestG
{
public:
void function()
{
}
};
class TestJ
{
public:
virtual void function()
{
}
};
class TestK: public TestJ
{
public:
void function() override
{
}
};
class TestL: virtual public TestJ
{
public:
void function() override
{
}
};
void main()
{
cout << "int:\t\t" << sizeof(int) << "\n";
cout << "TestA:\t\t" << sizeof(TestA) << "\t(empty class)\n";
cout << "TestB:\t\t" << sizeof(TestB) << "\t(inheriting empty class)\n";
cout << "TestC:\t\t" << sizeof(TestC) << "\t(virtual inheriting empty class)\n";
cout << "TestD:\t\t" << sizeof(TestD) << "\t(int class)\n";
cout << "TestE:\t\t" << sizeof(TestE) << "\t(inheriting int + int class)\n";
cout << "TestF:\t\t" << sizeof(TestF) << "\t(virtual inheriting int + int class)\n";
cout << "TestG:\t\t" << sizeof(TestG) << "\t(function class)\n";
cout << "TestH:\t\t" << sizeof(TestH) << "\t(inheriting function class)\n";
cout << "TestI:\t\t" << sizeof(TestI) << "\t(virtual inheriting function class)\n";
cout << "TestJ:\t\t" << sizeof(TestJ) << "\t(virtual function class)\n";
cout << "TestK:\t\t" << sizeof(TestK) << "\t(inheriting overriding function class)\n";
cout << "TestL:\t\t" << sizeof(TestL) << "\t(virtual inheriting overriding function class)\n";
cout << "\n";
system("pause");
}
de salida:
32 (x 86) bits:
int: 4
TestA: 1 (empty class)
TestB: 1 (inheriting empty class)
TestC: 4 (virtual inheriting empty class)
TestD: 4 (int class)
TestE: 8 (inheriting int + int class)
TestF: 12 (virtual inheriting int + int class)
TestG: 1 (function class)
TestH: 1 (inheriting function class)
TestI: 4 (virtual inheriting function class)
TestJ: 4 (virtual function class)
TestK: 4 (inheriting overriding function class)
TestL: 8 (virtual inheriting overriding function class)
64 (x64) bits:
int: 4
TestA: 1 (empty class)
TestB: 1 (inheriting empty class)
TestC: 8 (virtual inheriting empty class)
TestD: 4 (int class)
TestE: 8 (inheriting int + int class)
TestF: 24 (virtual inheriting int + int class)
TestG: 1 (function class)
TestH: 1 (inheriting function class)
TestI: 8 (virtual inheriting function class)
TestJ: 8 (virtual function class)
TestK: 8 (inheriting overriding function class)
TestL: 16 (virtual inheriting overriding function class)
Si desea información sobre herencia múltiple, ¡averígüelo usted mismo! -.-
Esta pregunta puede ser un poco más descriptiva con un título como "¿Cómo se determina el tamaño de un objeto en C++?". –
Here es un excelente libro sobre el tema. –