Почему siszeof (A) равно 1 и sizeof (C) тоже равно 1?
Функция в C
не является виртуальной, поэтому классу не нужен указатель vtable, поэтому ему не нужно больше памяти, чем A
. Ни A
, ни C
вообще не нужно никакого хранилища, но поскольку язык требует, чтобы разные экземпляры одного и того же класса имели разные указатели, они не могут иметь нулевой размер - поэтому компилятор делает их настолько маленькими, насколько это возможно, т.е. 1 байт.
Почему siszeof (H) равно 16, а sizeof (G) равно 4?
G
не имеет виртуальных функций, поэтому все, что нужно для хранения, это int, который в вашем компиляторе и архитектуре занимает 4 байта.
H
имеет виртуальные функции, поэтому класс должен содержать int
и указатель vtable. Все широко используемые компиляторы хранят указатель vtable в начале класса, поэтому макет равен {vptr, int}, что составляет 8 + 4 = 12 байт, если вы используете 64-битный хост.
Однако компилятор может дополнить это до 16 байтов, так что если в массиве будет выделено несколько экземпляров H
, то все они будут выровнены по словам. Это важно, поскольку при обращении к указателю (т. Е. К указателю vtable здесь) существуют значительные последствия для производительности, если он не выровнен по словам.
Почему siszeof (E) равно 16, а sizeof (F) равно 4?
E имеет виртуальные функции, поэтому ему нужен vtable ptr, поэтому его расположение аналогично H
. У F
нет виртуальных функций, у него есть только int, поэтому его макет такой же, как у G
. поэтому ответ такой же, как для G
и H
.
Порядок членов / функций здесь не имеет значения, потому что есть только одна переменная-член, и vtable ptr всегда идет первым, если он есть.
Почему siszeof (D) равно 8, а sizeof (E) - 16?
D
не имеет переменных-членов, но имеет виртуальную функцию, поэтому ему нужен указатель vtable. Указатель vtable - это единственное, что ему нужно, поэтому его размер равен sizeof(void*)
, что составляет 8 байт. E
требуется то же самое, что и D
, плюс 4 байта для целого числа, а компилятор округляет его до 16 байтов для выравнивания.