Давайте посмотрим на схему классов двух корпусов.
Без виртуального у вас есть два базовых класса ("X" и "Y") с целым числом каждый, и каждый из этих классов интегрировал в них базовый класс "Base", который также имеет целое число. Это 4 целых числа по 32 бита, каждый из которых содержит 16 байтов.
Offset Size Type Scope Name
0 4 int Base a
4 4 int X x
8 4 int Base a
12 4 int Y y
16 size (Z members would come at the end)
(Edit: я написал программу в DJGPP, чтобы получить макет и настроил таблицу, чтобы учесть это.)
Теперь давайте поговорим о виртуальных базовых классах: они заменяют фактический экземпляр класса указателем на общий экземпляр. Ваш класс "Z" имеет только один "базовый" класс, и оба экземпляра "X" и "Y" указывают на него. Следовательно, у вас есть целые числа в X, Y и Z, но у вас есть только один Z. Это означает, что у вас есть три целых числа или 12 байтов. Но X и Y также имеют указатель на общий Z (иначе они не знали бы, где его найти). На 32-битной машине два указателя добавят дополнительные 8 байтов. Итого 20, что вы видите. Схема памяти может выглядеть примерно так (я не проверял это ... у ARM есть пример, где порядок X, Y, Z, затем Base):
Offset Size Type Scope Name Value (sort of)
0 4 Base offset X ? 16 (or ptr to vtable)
4 4 int X x
8 4 Base offset Y ? 16 (or ptr to vtable)
12 4 int Y y
16 4 int Base a
20 size (Z members would come before the Base)
Таким образом, разница в памяти представляет собой комбинацию двух вещей: одно целое число меньше и еще два указателя. Вопреки другому ответу, я не верю, что vtables платит за это (редактирует) прямой (/ редактирует) просмотр, так как виртуальных функций нет.
Редактировать: ppinsider предоставил больше информации о случае gcc, в котором он демонстрирует, что gcc реализует указатель на виртуальный базовый класс, используя в противном случае пустой vtable (то есть, без виртуальных функций). Таким образом, если бы существовали виртуальные функции, для экземпляра класса не потребовался бы дополнительный указатель, что потребовало бы больше памяти. Я подозреваю, что недостатком является дополнительное косвенное обращение к базовому классу.
Мы можем ожидать, что все компиляторы сделают это, но, возможно, нет. На ARM стр. 225 обсуждаются виртуальные базовые классы без упоминания vtables. На странице 235 конкретно рассматриваются «виртуальные базовые классы с виртуальными функциями» и имеется схема, показывающая схему памяти, в которой есть указатели из частей X и Y, которые отделены от указателей на виртуальную таблицу. Я бы посоветовал никому не принимать как должное, что указатель на Base будет реализован в терминах таблицы.