Почему объект класса A занимает 4 байта?
#include <iostream>
struct F {};
struct D: F {};
struct E: F {};
struct B: D, E {};
struct C: D, E {};
struct A: B, C {};
int main() {
std::cout << sizeof(A{}) << '\n';
}
Правило "оптимизации пустых базовых классов" (empty base optimization) позволяет пустым базовым подобъектам иметь размер 0 в составе объекта-наследника. Однако в то же время два различных базовых подобъекта одного и того же типа обязаны иметь разные адреса, даже если они пусты. У вас в вашей иерархии в классе A набирается как минимум 4 различных базовых подобъекта типа F. Это уже требует размера как минимум в 4 минимальных адресуемых единицы памяти.
Если сделать
int main()
{
A a;
std::cout << sizeof a << std::endl;
std::cout << &a << std::endl;
std::cout << (F *)(D *)(B *) &a << std::endl;
std::cout << (F *)(E *)(B *) &a << std::endl;
std::cout << (F *)(D *)(C *) &a << std::endl;
std::cout << (F *)(E *)(C *) &a << std::endl;
}
то получаем (GCC, Clang)
4
0x7ffcc5ed5f5c
0x7ffcc5ed5f5c
0x7ffcc5ed5f5d
0x7ffcc5ed5f5e
0x7ffcc5ed5f5f
MSVC++, похоже, полагает, что для последнего (по порядку в памяти) подобъекта F нужен лишь уникальный адрес, но не нужно фактического байта памяти, по каковой причине размер A получается равным 3. Это нехорошо, ведь какой-то другой - внешний по отношению к A - объект может разместиться по тому же адресу, что и последнее F в A.
Проверим
struct X
{
A a;
char c;
};
int main()
{
X a;
std::cout << sizeof a << std::endl;
std::cout << &a << std::endl;
std::cout << (F *)(D *)(B *) &a.a << std::endl;
std::cout << (F *)(E *)(B *) &a.a << std::endl;
std::cout << (F *)(D *)(C *) &a.a << std::endl;
std::cout << (F *)(E *)(C *) &a.a << std::endl;
std::cout << (void *) &a.c << std::endl;
}
получаем
3
000000B30CEFFA44
000000B30CEFFA44
000000B30CEFFA45
000000B30CEFFA46
000000B30CEFFA47
000000B30CEFFA47
Если я не ошибаюсь, совпадение адресов (F *)(E *)(C *) &a.a и &a.c является нарушением требований спецификации языка, т.е. багом в MSVC++.
В C++ стандарте размер структуры должен иметь минимум один байт.
1.8 The C ++ object model
Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage.
Структура F имеет размер один байт. D = F + 0 = 1 . B = D + E = 1 + 1 = 2 . A = B + C = 2 + 2 = 4 .
Сборка персонального компьютера от Artline: умный выбор для современных пользователей