Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ООП.doc
Скачиваний:
23
Добавлен:
08.11.2018
Размер:
1.4 Mб
Скачать
  1. Внутреннее устройство объекта

Рассмотрим, что представляет собой объект с точки зрения его внутренней организации. Как уже было сказано выше, объект в Object Pascal – это указатель. Пока объект не создан, значение указателя не определено или равно nil. После создания объекта путем вызова конструктора этот указатель указывает на некоторую структуру, содержащую, в частности все поля объекта.

Методы класса, как известно, подразделяются на статические, виртуальные и динамические. Адрес статических методов определяется еще на стадии компиляции проекта, поэтому никакой дополнительной информации о них не требуется. Компилятор просто подставляет в нужное место адрес метода. Связь между соответствующим набором полей и методом устанавливается путем неявной передачи параметра this, указывающего на конкретный экземпляр объекта. Понятно, что этот тип методов вызывается быстрее всего.

В случае виртуальных и динамических методов, как уже говорилось, будет вызываться метод, соответствующий реальному типу созданного объекта, а не типу указателя. То есть, на стадии компиляции нет возможности определить фактический класс объекта, метод которого должен быть вызван. Нужен механизм, позволяющий определять это прямо во время выполнения программы – это называется поздним связыванием. В качестве такого механизма в Object Pascal используются таблица виртуальных методов (Virtual Method Table, VMT) и таблица динамических методов (Dynamic Method Table, DMT).

Рассмотрим пример:

Interface Type TObject1 = class(TObject) FMyField1: integer; FMyField2: integer; Procedure StateMethod; Procedure VirtualMethod1; virtual; Procedure VirtualMethod2; virtual; Procedure DynamicMethod1; dynamic; Procedure DynamicMethod2; dynamic; End;

TObject2 = class(TObject1) FMyField3: integer; Procedure StatMethod; Procedure VirtMethod1; override; Procedure DynaMethod1; override; End;

Var Obj1: TObject1; Obj2: TObject2;

Implementation procedure Test; begin Obj1 := TObject1.Create; Obj2 := TObject2.Create; end;

Внутренняя структура двух рассматриваемых объектов будет выглядеть, как показано на рис. 17.

Итак, переменная типа класс хранится как 32-битовый указатель на экземпляр класса, называемый объектом. Внутренний формат данных объекта представляет собой запись. Поля объекта хранятся в порядке описания как последовательность переменных, занимающих смежные адреса памяти. Поля всегда выровнены в соответствии с установленным для компилятора типом упаковки записи. Например, если тип упаковки двойное слово, то под каждое поле отводится целое число двойных слов, даже если реальный тип поля байт. Все поля, унаследованные из класса-предка, хранятся перед новыми полями, определенными в классе-потомке.

Первое 4-х байтовое поле каждого объекта представляет собой указатель на таблицу виртуальных методов класса. Имеется строго одна VMT на класс (а не на объект). Различающиеся классы, вне зависимости от того, насколько они похожи, никогда не разделяют VMT. Таблицы виртуальных методов классов автоматически создаются компилятором. Непосредственная работа с ними из программы невозможна. Указатели на таблицы виртуальных методов, которые автоматически устанавливаются конструктором во время создания объекта, также никогда не используются программой непосредственно.

Рассмотрим содержание таблицы виртуальных методов. Начиная с адреса, на который ссылается объект, в направлении положительного смещения VMT содержит список 32-битовых указателей на методы – по одному на каждый определенный пользователем виртуальный метод класса в порядке объявления. Каждый из этих указателей содержит адрес точки входа соответствующего виртуального метода. Эта часть VMT является стандартной. Аналогичные таблицы строятся компиляторами С++. Совместима с COM.

В направлении отрицательного смещения, т.е. перед адресом, на который ссылается объект, VMT содержит специальную, внутреннюю для Object Pascal, структуру с дополнительной информацией. В ней содержатся данные, полностью характеризующие класс: его имя, размер экземпляра, указатели на класс-предок, имя класса и т.д. Эта информация может быть полезна программисту. Она доступна через методы класса TObject, работать с ее структурой непосредственно не рекомендуется, так как она может измениться в последующих версиях Object Pascal.

Одно из полей этой структуры содержит адрес таблицы динамических методов класса (DMT). Таблица имеет следующий формат: в начале слово, содержащее количество элементов таблицы, затем слова, соответствующие индексам методов. Нумерация индексов начинается с –1 и идет по убывающей. После индексов идут собственно адреса динамических методов. Причем в DMT находятся адреса только тех методов, которые были описаны или перекрыты именно в этом классе. Адреса методов, описанных в классе-предке и не перекрытых в классе-потомке, находятся в DMT класса-предка.

Далее сравним виртуальные и динамические методы. Виртуальные и динамические методы по своему назначению одинаковы. Разница заключается в особенностях поиска их адреса. Когда компилятор встречает обращение к виртуальному методу, он подставляет вместо прямого вызова по конкретному адресу код, который обращается к VMT и извлекает оттуда нужный адрес. В VMT хранятся адреса всех виртуальных методов класса, независимо от того, унаследованы ли они от предка или перекрыты в данном классе. Отсюда и достоинства и недостатки виртуальных методов: они вызываются сравнительно быстро, однако для хранения указателей на них в таблице VMT требуется большое количество памяти.

Динамические методы вызываются медленнее, но позволяют экономить память. Каждому динамическому методу системой присваивается уникальный индекс. В таблице динамических методов класса хранятся индексы и адреса только тех динамических методов, которые описаны или перекрыты в данном классе. При вызове динамического метода происходит поиск в этой таблице; в случае неудачи просматриваются DMT всех классов-предков в порядке иерархии заканчивая TObject. Указатели на класс-предок при этом извлекается из VMT текущего класса. Динамические методы, таким образом, экономят память за счет потери быстродействия.

Как правило, рекомендуется использовать виртуальные методы, как представляющие собой более эффективный способ реализации полиморфизма. Динамические методы полезны, когда в базовом классе описано большое число перекрываемых методов, которые наследуются многочисленными потомками, но перекрываются редко.