Меня всегда интересовали подобные вещи, поэтому я решил дать полный ответ. Речь идет о том, что вы можете ожидать, и это предсказуемо (yay)! Таким образом, используя приведенную ниже информацию, вы должны быть в состоянии предсказать размер класса.
Используя Visual Studio Community 2017 (версия 15.2), в режиме выпуска со всеми отключенными оптимизациями и RTTI ( Информация о типе времени выполнения ) выключена , я определил следующее:
Краткий ответ:
Прежде всего:
- В 32 (x86) бита,
<size of pointer> == 4
байтов
- В 64 (x64) битах,
<size of pointer> == 8
байтах
- Когда я говорю «наследование виртуального класса», я имею в виду, например:
class ChildClass: virtual public ParentClass
Итак, мои выводы таковы:
- пустые классы по 1 байту
- наследование пустого класса по-прежнему 1 байт
- пустые классы с функциями по-прежнему 1 байт (?! См. Примечание для пояснения ниже)
- наследование пустого класса с функцией по-прежнему составляет 1 байт
- добавление переменной в пустой класс составляет
<size of variable>
байт
- наследование класса с переменной и добавление другой переменной
<size of variables>
байт
- наследование класса и переопределение его функции добавляет vtable (дальнейшее объяснение приведено в разделе Выводы ) и составляет
<size of pointer>
байт
- простое объявление функции виртуальной также добавляет vtable, делая его
<size of pointer>
байт
- Наследование виртуального класса пустого класса (с или без функции-члена) также добавляет vtable и делает класс
<size of pointer>
байтами
- наследование виртуального класса непустого класса также добавляет vtable, но это несколько усложняется: оно добавляет
<size of pointer>
байтов к общему количеству, обертывание всего члена переменные с шагом <size of pointer>
байтов, необходимым для покрытия <total size of member variables>
- да, вы правильно прочитали ... (см. мое предположение относительно того, что происходит в Выводы ...)
Обратите внимание , что я даже пытался заставить функцию () вырезать некоторый текст, создать экземпляр класса и вызвать функцию; это не меняет размер класса функции (это не оптимизация)! Я был несколько удивлен, но на самом деле это имеет смысл: функции-члены не меняются, поэтому они могут храниться вне самого класса.
Выводы:
- Пустые классы имеют размер 1 байт, поскольку это минимум, необходимый для присутствия в памяти. После добавления данных или данных vtable начните отсчет с 0 байтов.
- Добавление ( не виртуальной ) функции-члена никак не влияет на размер, поскольку функция-член хранится извне.
- Объявление функции-члена виртуальной (даже если класс не переопределен!) Или переопределение функции-члена в дочернем классе добавляет то, что называется "vtable" или "таблица виртуальных функций" , который позволяет Dynamic Dispatch (что действительно очень круто в использовании, хотя я настоятельно рекомендую его использовать). Эта таблица занимает
<size of pointer>
байтов, добавляя <size of pointer>
байтов к указанному классу. Эта таблица может существовать только один раз для каждого класса (конечно, она есть или нет).
- Добавление переменной-члена увеличивает размер класса на эту переменную-член независимо от того, входит ли указанная переменная-член в родительский или дочерний класс (хотя, конечно, родительский класс остается своего собственного размера).
- Наследование виртуальных классов - единственная часть, которая усложняется ... Итак ... Я думаю, что происходит после небольшого эксперимента: размер класса фактически увеличивается на
<size of pointer>
байт за раз, даже если мне не нужно тратить столько памяти, я полагаю, потому что он добавляет vtable «вспомогательный блок» для каждого <size of pointer>
байтов памяти или чего-то еще ...
Длинный ответ:
Я определил все это, используя этот код:
#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");
}
Выход:
32 (x86) бит:
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) бит:
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)
Если вы хотите получить информацию о множественном наследовании, иди разберись с ней! -.-