class Foo {};
class Bar {
Foo f;
int i;
};
Класс Foo является пустым. Как известно, размер любого объекта пустого класса как - минимум - равен 1 байту (для большинства компиляторов):
sizeof(Foo) == 1
Это достигается молчаливой вставкой компилятором одного байта (char) в такой пустой объект. Теперь посмотрим на размер класса Bar:
sizeof(Bar) == 2 * sizeof(int)
В данном случае объект класса Foo занимает 1 байт с выравниванием до размера члена i sizeof(int). Это связано с тем, что два базовых подобъекта одного типа должны иметь разные адреса.
Теперь организуем класс Bar с помощью наследования следующим образом:
class Bar : public Foo {
int i;
};
И снова посмотрим на размер класса Bar:
sizeof(Bar) == sizeof(int)
В итоге мы видим, что компилятор при таком раскладе под подобъект Foo выделил 0 байт. В этом и состоит идея оптимизации пустого базового класса. В стандарте по этому поводу сказано:
A class with an empty sequence of [data] members and base class objects is an empty class. Complete objects and member subobjects of an empty class type shall have nonzero size.
Что мы и видим на деле. Всем успехов.