Вопрос на множественном наследовании, виртуальных базовых классах и размере объекта в C++

Попробуйте это:

package:
  exclude:
    - '*/**'
  include:
    - 'lib/**'
    - '!./lib/dir/DirIdontWantBecauseTheSizeIsTooLarge'
    - '!./lib/dir/DirButNotOneSubdir/DirIdontWantBecauseTheSizeIsTooLarge'

Он должен включать в себя все, что указано в lib/, за исключением файлов, которые вы указали не делать. Используя ! , вы можете пометить файлы и каталоги, которые нужно пропустить на этапе включения.

12
задан Shog9 28 December 2008 в 17:19
поделиться

3 ответа

Давайте посмотрим на расположение класса этих двух случаев.

Без виртуального у Вас есть два базовых класса ("X" и "Y") с целым числом каждый, и каждый из тех классов интегрировал в них "Основной" базовый класс, который также имеет целое число. Это - 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)

(Редактирование: я записал программу в DJGPP для получения расположения и настроил таблицу для составления его.)

Теперь давайте говорить о виртуальных базовых классах: они заменяют фактический экземпляр класса с указателем на общий экземпляр. Ваш "Z" класс имеет только один "Основной" класс, и оба экземпляра "X" и "Y" указывают на него. Поэтому у Вас есть целые числа в X, Y, и Z, но у Вас только есть один Z. Это означает, что у Вас есть три целых числа, или 12 байтов. Но X и Y также имеют указатель на общий Z (иначе, они не знали бы, где найти его). На 32-разрядной машине два указателя добавят дополнительные 8 байтов. Это составляет 20, что Вы видите. Расположение памяти могло бы выглядеть примерно так (я не проверил его... ARM имеет пример, где упорядочивание X, Y, Z, затем Основа):

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 (т.е. никакие виртуальные функции). Тот путь, если бы были виртуальные функции, это не потребовало бы дополнительного указателя в экземпляре класса, требуя большей памяти. Я подозреваю, что оборотная сторона является дополнительной косвенностью для получения до базового класса.

Мы могли бы ожидать, что все компиляторы сделают это, но возможно нет. Страница 225 ARM обсуждает виртуальные базовые классы, не упоминая vtables. Страница 235 конкретно обращается "к виртуальным базовым классам с виртуальными функциями" и имеет схему, указывающую на расположение памяти, откуда существуют указатели частей X и Y, которые являются отдельными от указателей до vtable. Я советовал бы любому не брать для предоставленного, что указатель на Основу будет реализован с точки зрения таблицы.

20
ответ дан 2 December 2019 в 04:43
поделиться

Дополнительный размер, вероятно, из-за дополнительного VTables (http://en.wikipedia.org/wiki/Vtable), выделенный виртуальными классами и множественным наследованием.

3
ответ дан 2 December 2019 в 04:43
поделиться

Ответ Mark Santesson находится в значительной степени на деньгах, но assertation, что нет никаких vtables, является неправильным. Можно использовать g ++ - fdump-иерархия-классов для показа то, что продолжается. Вот не virtuals случай:

Class Base
   size=4 align=4
   base size=4 base align=4
Base (0x19a8400) 0

Class X
   size=8 align=4
   base size=8 base align=4
X (0x19a8440) 0
  Base (0x19a8480) 0

Class Y
   size=8 align=4
   base size=8 base align=4
Y (0x19a84c0) 0
  Base (0x19a8500) 0

Class Z
   size=16 align=4
   base size=16 base align=4
Z (0x19b1800) 0
  X (0x19a8540) 0
    Base (0x19a8580) 0
  Y (0x19a85c0) 8
    Base (0x19a8600) 8

Обратите особое внимание на "основной размер" аргумент. Теперь virtuals случай и показ только Z:

Class Z
   size=20 align=4
   base size=16 base align=4
Z (0x19b3000) 0
    vptridx=0u vptr=((& Z::_ZTV1Z) + 12u)
  X (0x19a8840) 0
      primary-for Z (0x19b3000)
      subvttidx=4u
    Base (0x19a8880) 16 virtual
        vbaseoffset=-0x0000000000000000c
  Y (0x19a88c0) 8
      subvttidx=8u vptridx=12u vptr=((& Z::_ZTV1Z) + 24u)
    Base (0x19a8880) alternative-path

Обратите внимание, что "основной размер" является тем же, но "размер" является одним указателем больше, и обратите внимание, что существует теперь vtable указатель! Это в свою очередь содержит конструкцию vtables для родительских классов и всего волшебства межкласса (конструкция vtables и виртуальная таблица таблицы (VTT)), как описано здесь:

http://www.cse.wustl.edu/~mdeters/seminar/fall2005/mi.html

Обратите внимание, что фактическая функциональная vtable отправка будет пуста.

9
ответ дан 2 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: