Ответ 1
Так получилось, что ваш класс Base
имеет 8-байтовое требование выравнивания, но его последний член имеет размер 4. Это приводит к пустой области заполнения, добавленной в конце макета памяти Base
. Это дополнительное дополнение играет свою роль, когда вы создаете объекты класса Base
сами по себе, как так называемые наиболее производные объекты.
Base b; // <- a most-derived object
Base a[10]; // <- an array of most-derived objects
Однако, когда вы "внедряете" Base
в качестве базового класса в класс Derived
, нет необходимости в дополнительном дополнении в конце встроенного субъекта Base
.
Derived d; // <- object `d` contains an embedded sub-object of type `Base`
Интеллектуальный компилятор попытается повторно использовать эту область, поместив дополнительное поле класса Derived
в область макета, используемую для заполнения в Base
. В вашем случае дополнительное поле Derived::f
, кстати, имеет тот же размер 4 байта, то есть идеально вписывается в него. Конечным результатом является то, что общий размер класса не увеличивается.
Очень похожий (по природе) эффект - это так называемая "пустая оптимизация базы". В С++ sizeof
для любого типа гарантированно будет больше 0, что означает, что sizeof
пустого класса всегда больше нуля. Однако, когда вы получаете какой-либо другой класс из пустого базового класса, вы можете заметить, что базовый класс вносит ровно 0 байтов в размер производного класса. Например
struct A {};
struct B {};
struct C {};
struct D {};
struct F : A, B, C, D {
int i;
}
int main() {
std::cout << sizeof(A) << std::endl << sizeof(B) << std::endl <<
sizeof(C) << std::endl << sizeof(D) << std::endl;
std::cout << sizeof(F) << std::endl;
}
Несмотря на то, что sizeof
для каждого базового класса больше нуля, sizeof(F)
обычно будет оцениваться до sizeof(int)
, как будто подобъекты базового класса вообще не существуют.
Другими словами, как показывают такие примеры, субобъекты базового класса следуют значительно более расслабленным правилам в отношении их макета памяти, чем большинство производных объектов. Эти непринужденные правила могут легко привести к ситуациям, когда sizeof
базового класса будет лишь частично способствовать sizeof
производного класса.