Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Паскаль / tp3 / tp3 / 17.doc
Скачиваний:
17
Добавлен:
10.12.2013
Размер:
112.64 Кб
Скачать

Глава 17. Объекты

Внутренние форматы данных объектов

Внутренний формат данных объекта имеет сходство с внутренним форматом записи. Поля объекта записываются в порядке их описаний как непрерывная последовательность переменных. Любое поле, унаследованное от родительского (порождающего) типа, записывается перед новыми полями, определенными в производном (порожденном) типе.

Если объектный тип определяет виртуальные методы, конструктор или деструктор, то компилятор размещает в объектном типе дополнительное поле данных. Это 16-битовое поле, называемое полем таблицы виртуальных методов (ТВМ), используется для запоминания смещения таблицы виртуальных методов в сегменте данных. Поле таблицы виртуальных методов следует непосредственно после обычных полей объектного типа. Если объектный тип наследует виртуальные методы, конструкторы или деструкторы, то он также наследует и поле ТВМ, благодаря чему дополнительное поле таблицы виртуальных методов не размещается.

Инициализация поля таблицы виртуальных методов экземпляра объекта осуществляется конструктором (или конструкторами) объектного типа. Программа никогда не инициализирует поле таблицы виртуальных методов явно и не имеет к нему доступа.

Следующие примеры иллюстрируют внутренние форматы данных объектных типов.

type

TLocationPtr = ^Location;

PLocation = object

X,y: integer;

procedure Init(PX, PY: integer);

function GetX: integer;

function GetY: integer;

end;

PPointPtr = ^Point;

TPoint = object(Location)

Color: integer;

constructor Init(PX, PY, PColor: integer);

destructor Done; virtual;

procedure Show; virtual;

procedure Hide; virtual;

procedure MoveTo(PX, PY: integer); virtual;

end;

PCirclePtr = ^Circle;

TCircle = object(Point)

Radius: integer;

constructor Init(PX, PY, PColor, PRadius: integer);

procedure Show; virtual;

procedure Hide; virtual;

procedure Fill; virtual;

end;

Рисунок 17.1 показывает размещение экземпляров типов TLocation, TPoint и TCircle: каждый прямоугольник соответствует одному слову памяти.

TLocation TPoint TCircle

┌───────────┐ ┌───────────┐ ┌───────────┐

│ X │ │ X │ │ X │

├───────────┤ ├───────────┤ ├───────────┤

│ Y │ │ Y │ │ Y │

└───────────┘ ├───────────┤ ├───────────┤

│ Color │ │ Color │

├───────────┤ ├───────────┤

│ NDV │ │ NDV │

└───────────┘ ├───────────┤

│ Radius │

└───────────┘

Рис. 17.1 Схема экземпляров типов TLocation, TPoint и TCircle

Таблица виртуальных методов

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

Первое слово таблицы виртуальных методов содержит размер экземпляров соответствующего объектного типа. Эта информация используется конструкторами и деструкторами для определения того, сколько байт выделяется или освождается при использовании расширенного синтаксиса стандартных процедур New и Dispose.

Второе слово таблицы виртуальных методов содержит отрицательный размер экземпляров соответствующего объектного типа эта информация используется ратификационным (т.е. подтверждающим действительность) механизмом вызова виртуального метода для выявления инициализируемых объектов (экземпляров, для которых должен выполняться конструктор) и для проверки согласованности таблицы виртуальных методов. Когда разрешена ратификация виртуального вызова (с помощью директивы {$R+} компилятора, которая расширена и включает в себя проверку виртуальных методов), компилятор генерирует вызов программы проверки допустимости таблицы виртуальных методов перед каждым вызовом виртуального метода. Программа ратификации таблицы виртуальных методов проверяет, что первое слово таблицы виртуальных методов не равно нулю и что что сумма первого и второго слов равна нулю. Если любая из проверок неудачна, то генерируется ошибка 210 исполняющей системы Турбо Паскаля.

Разрешение проверок границ диапазонов и проверок вызовов виртуальных методов замедляет выполнение программы и делает ее несколько больше, поэтому используйте {$R+} только во время отладки и переключите эту директиву в состояние {$R-} в окончательной версии программы.

Третье слово ТВМ содержит смещение сегмента данных объектного типа в таблице динамических методов (ТДМ), или 0, если объект не содержит динамических методов.

Четвертое слово ТВМ резервируется и всегда равно 0.

Наконец, начиная со смещения 8 таблицы виртуальных методов следует список 32-разрядных указателей методов (один указатель на каждый виртуальный метод в порядке их описаний). Каждая позиция содержит адрес точки входа соответствующего виртуального метода.

На Рис. 17.2 показано размещение таблиц виртуальных методов типов TPoint и TCircle (тип TLocation не имеет таблицы виртуальных методов, т.к. не содержит в себе виртуальных методов, конструкторов и деструкторов): каждый маленький прямоугольник соответствует одному слову памяти, а каждый большой прямоугольник - двум словам памяти.

ТВМ TPoint ТВМ TCircle

┌──────────────────┐ ┌──────────────────┐

│ $0008 │ │ $000A │

├──────────────────┤ ├──────────────────┤

│ $FFFB │ │ $FFF6 │

├──────────────────┤ ├──────────────────┤

│ │ │ │

│ @TPoint.Done │ │ @TPoint.Done │

├──────────────────┤ ├──────────────────┤

│ │ │ │

│ @TPoint.Show │ │ @TCircle.Show │

├──────────────────┤ ├──────────────────┤

│ │ │ │

│ @TPoint.Hide │ │ @TCircle.Hide │

├──────────────────┤ ├──────────────────┤

│ │ │ │

│ @TPoint.MoveTo │ │ @TPoint.MoveTo │

└──────────────────┘ ├──────────────────┤

│ │

│ @Circle.Fill │

└──────────────────┘

Рис. 17.2 Схемы таблиц виртуальных методов для TPoint и TCircle

Обратите внимание на то, как Circle наследует методы Done и MoveTo типа Point и как он переопределяет Show и Hide.

Как уже упоминалось, конструкторы объектных типов содержат специальный код, который запоминает смещение таблицы виртуальных методов объектного типа в инициализируемых экземплярах. Например, если имеется экземпляр P типа TPoint и экземпляр C типа TCircle, то вызов P.Init будет автоматически записывать смещение таблицы виртуальных методов типа TPoint в поле таблицы виртуальных методов экземпляра P, а вызов C.Init точно так же запишет смещение таблицы виртуальных методов типа TCircle в поле таблицы виртуальных методов экземпляра C. Эта автоматическая инициализация является частью кода входа конструктора, поэтому если управление передается в начало операторной секции, то поле Self таблицы виртуальных методов также будет установлено. Таким образом, при возникновении необходимости, конструктор может выполнить вызов виртуального метода.

Таблица динамических методов

Таблица вирутальных методов (ТДМ) объектного типа содержит для каждого описанного в объектном типе виртуального метода и его предков четырехбайтовую запись. В тех случаях, когда в порождающих типах (предках) определяется большее число виртуальных методов, в процессе создания производных типов может использоваться достаточно большой объем памяти, особенно если создается много производных типов. Хотя в производных типах могут переопределяться только некоторые из наследуемых методов, таблица вирутальных методов каждого производного типа содержит указатели метода для всех наследуемых виртуальных методов, даже если они не изменялись.

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

Формат таблицы динамических методов иллюструют следующие два объектных типа:

type

TBase = object

Соседние файлы в папке tp3