Здравствуйте! На этой лекции мы продолжим изучать хранение объектов в памяти. И сегодня мы рассмотрим случай, когда объекты наследуются друг от друга — то есть еще более сложные случай, чем на прошлой лекции. Наш самый главный класс, на который мы будем смотреть, — это структура "Outer", которая наследуется от двух базовых типов — от "Base1" и "Base2". "Base1" и "Base2" — очень простые структуры. Они сдержат по паре полей элементарных типов — "int", "char" и "bool", "float", размеры которых равны четыре и один байта, вы это уже знаете. Что мы хотим сделать? Как и всегда, мы хотим узнать, какой размер у структуры "Outer" и как внутри она устроена, где у нее расположены ее поля. Давайте запустим нашу программу. Так, вот уже знакомый макрос вам по прошлому занятию сообщает нам, что для базовых классов "sizeoff" равен восемь, они выровнены по границе четыре байта. И класс "Outer" имеет размер 20 байтов и выравнен по границе четыре байта. Согласитесь, это очень похоже на тот случай, которы мы рассматривали на прошлом занятии. На что мы еще можем посмотреть, прежде чем попробовать нарисовать схему расположения байтов в памяти? Мы можем вспомнить, что у нас есть ключик "Wpadded". Я, на самом деле, компилировал уже с ним. Давайте посмотрим на результаты компиляции. Что нам сообщают? Что у нас в тип "Outer" добавлены два байта в конец, два байта "padding" для выравнивания. Что в структуру "Base2" добавлены три байта для того, чтобы выровнять "f", и так далее. Но, к сожалению, этой информации нам недостаточно, чтобы нарисовать картинку. Мы сейчас не можем воспользоваться макросом "offsetof" для изучения схемы расположения объекта "Outer" в памяти, потому что "offsetof" умеет работать только с полями, а не с базовыми классами. Но мы можем найти инструмент даже мощнее — мы можем воспользоваться специальным флагом компилятора. Этот флаг называется "fdump-record-layouts", и как можно догадаться из его названия, он печатает полностью расположение, схему объектов в памяти. Если мы его запустим просто так, он нам напечатает очень много информации, в которой нам трудно разобраться. Давайте попробуем в этой информации найти нужный нам фрагмент. Поищем здесь упоминание типа "Outer". К счастью, мы его быстро нашли. Вот он. И рядом с ним у нас даже написана информация про структуры "Base1" и "Base2". Мы видим, что структура "Base1" состоит из полей "int" и "char" — вот их смещение, "sizeof" структуры равен восемь байтов. "Base2" также состоит из типов "_Bool" и "float" — вот их смещение, "sizeof" — восемь байтов. И вот структура "Outer" тоже здесь приведена. Она состоит из базового класса "Base1", который идет в начале этой структуры. За ней следует базовый класс "Base2", расположен в памяти сразу за "Base1". И после базовых классов — то поле, которое определено в классе "Outer", и "sizeof" всей структуры равен 20 байтов. Видите, какой удобный параметр для компилятора мы узнали. Посмотрим на слайды. Чтобы было удобнее смотреть на вывод компилятора, я скопировал интересующую вас информацию на слайд. Здесь схематично изображено устройство объектов в памяти и все смещения от начала объектов в байтах. Посмотрите на слайд, на соответствие между кодом и устройством памяти. И перейдем дальше к картинкам, как обычно. Здесь привычно отображены разными цветами разные элементарные типы данных, а серый цвет — это "padding". Схема нарисована в соответствии с выводом компилятора. Обратите внимание, как сильно эта схема похожа на схему из прошлого урока. Разница только в коде. В прошлый раз мы рассматривали поля в классах, а сейчас — наследование. Но физически, с точки зрения хранения в памяти, это оказывается эквивалентным. Главный итог этой лекции — это то, что при наследовании объекты базовых типов расположены в памяти точно так же, как если бы были объявлены полями в самом начале. Если базовых объектов несколько, то они расположатся в памяти так же, в том же порядке, один за одним. Кстати сказать, конструироваться такие объекты будут также в том же порядке. Но об этом мы поговорим на следующих лекциях.