Слайд 1Внутреннее представление объектов
Слайд 2Внутренний формат данных объекта.
Внутренний формат данных объекта имеет сходство с
внутренним форматом записи.
Поля объекта записываются в порядке их описаний как
непрерывная последовательность переменных.
Любое поле, унаследованное от родительского (порождающего) типа, записывается перед новыми полями, определенными в дочернем (порожденном) типе.
Слайд 3Внутренний формат данных объекта.
Если объектный тип определяет виртуальные методы, конструкторы
или деструкторы, то компилятор размещает в нем дополнительное поле данных.
Это
16-битовое поле, называемое полем таблицы виртуальных методов, используется для запоминания смещения таблицы виртуальных методов в сегменте данных.
Поле таблицы виртуальных методов располагается непосредственно после обычных полей объектного типа.
Если объектный тип наследует виртуальные методы, конструкторы или деструкторы, то он также наследует и поле ТВМ.
Благодаря чему дополнительное поле таблицы виртуальных методов не размещается.
Слайд 4Внутренний формат данных объекта.
Инициализация поля таблицы виртуальных методов экземпляра объекта
осуществляется конструктором объектного типа.
Программа никогда не инициализирует поле таблицы виртуальных
методов явно и
не имеет к нему доступа.
Слайд 5Представление в сегменте данных объектов типов TPerson, TStaff и Tteacher.
TPerson
Name
Date
Rate
TBM
TStaff
Name
Date
Rate
TBM
Bonus
TTeacher
Name
Date
Rate
TBM
Bonus
Hours
HourRate
Слайд 6Таблица виртуальных методов.
Каждый объектный тип, содержащий или наследующий виртуальные методы,
конструкторы или деструкторы, имеет таблицу виртуальных методов.
В таблице виртуальных методов
запоминается инициализируемая часть сегмента данных программы.
Для каждого объектного типа
(но не для каждого экземпляра)
имеется только одна таблица виртуальных методов
Два различных объектных типа никогда не разделяют одну таблицу виртуальных методов, независимо от того, насколько эти типы идентичны.
Таблицы виртуальных методов создаются компилятором автоматически, и программа никогда не манипулирует ими непосредственно.
Указатели на таблицы виртуальных методов также запоминаются автоматически в экземплярах объектных типов с помощью конструкторов.
Программа никогда не работает непосредственно с этими указателями.
Слайд 7Таблица виртуальных методов.
Первое слово таблицы виртуальных методов содержит размер экземпляров
соответствующего объектного типа.
Эта информация используется конструкторами и деструкторами для
определения количества байтов, которое выделяется или освобождается при использовании расширенного синтаксиса стандартных процедур New и Dispose.
Слайд 8Таблица виртуальных методов.
Второе слово таблицы виртуальных методов содержит отрицательный размер
экземпляров соответствующего объектного типа.
Эта информация используется программой контроля вызовов виртуальных
методов для выявления неинициализированных объектов (экземпляров, для которых не был произведен вызов конструктора) и для проверки правильности таблицы виртуальных методов.
Если разрешен контроль виртуального вызова с помощью директивы {$R+}, компилятор генерирует вызов подпрограммы контроля обращения к таблице виртуальных методов перед каждым вызовом виртуального метода.
Эта подпрограмма проверяет неравенство первого слова ТВМ нулю и равенство суммы первого и второго слов нулю.
Если каждая из проверок обнаруживает несовпадение, то генерируется ошибка выполнения с кодом 210.
Слайд 9Таблица виртуальных методов.
Разрешение проверок границ диапазонов и проверок вызовов виртуальных
методов замедляет выполнение программы и делает размер ЕХЕ-файла немного большим,
поэтому рекомендуется использовать директиву {$R+} только во время отладки и переключать эту директиву в состояние {$R-} в окончательной версии программы.
Слайд 10Таблица виртуальных методов.
Третье слово ТВМ содержит смещение сегмента данных объектного
типа в таблице динамических методов (ТДМ) или 0, если объект
не содержит динамических методов.
Слайд 11Таблица виртуальных методов.
Четвертое слово ТВМ резервируется и всегда равно 0.
Слайд 12Таблица виртуальных методов.
Начиная со смещения 8,
следует список 32-разрядных указателей
методов.
Один указатель на каждый виртуальный метод в порядке их
описания
Каждая позиция содержит адрес точки входа соответствующего виртуального метода.
Слайд 13Пример размещения таблиц виртуальных методов типов TStaff и TTeacher
TBM TStaff
16
-16
0
0
TStaff.Done
TStaff.GetSum
TStaff.ShowSum
TStaff.ShowAll
TBM TTeacher
16
-16
0
0
TTeacher.Done
TTeacher.GetSum
TTeacher.ShowSum
TTeacher.ShowAll
одно слово памяти
два слова памяти
Слайд 14Таблица виртуальных методов.
Конструкторы объектных типов содержат специальный код, который запоминает
смещение таблицы виртуальных методов объектного типа в инициализируемых экземплярах.
Например:
Пусть у
нас имеется
экземпляр S типа TStaff и
экземпляр Т типа Ттеасher
вызов S.Init будет автоматически записывать смещение таблицы виртуальных методов типа TStaff в поле таблицы виртуальных методов экземпляра S
а вызов T.Init точно так же запишет смещение таблицы виртуальных методов типа ТТеасher в поле таблицы виртуальных методов экземпляра Т.
Эта автоматическая инициализация является частью кода входа конструктора, поэтому если управление передается в начало операторной секции, то поле таблицы виртуальных методов параметра Self также будет установлено.
Таким образом, при необходимости конструктор может выполнить вызов виртуального метода.
Слайд 15Функции для работы с таблицей виртуальных методов.
Для непосредственной работы с
ТВМ используются две функции
FUNCTION SizeOf(Obj):WORD;
FUNCTION TypeOf(Obj):POINTER;
Слайд 16Функции для работы с таблицей виртуальных методов.
Примененная к экземпляру объектного
типа, имеющего таблицу виртуальных методов, функция SizeOf вернет записанный в
таблице виртуальных методов размер.
Таким образом, для объектов, имеющих таблицу виртуальных методов, функция SizeOf всегда возвращает действительный размер экземпляра, а не приведенный в описании.
Функция TypeOf возвращает указатель на таблицу виртуальных методов объектного типа.
Функция TypeOf принимает единственный параметр, который может быть либо идентификатором объектного типа, либо экземпляром объектного типа.
В обоих случаях результат типа POINTER является указателем на таблицу виртуальных методов объектного типа.
TypeOf может применяться только к объектным типам, имеющим таблицы виртуальных методов.
Применение этой функции к другим типам приведет к ошибке.
Слайд 17Функции для работы с таблицей виртуальных методов.
Функция TypeOf может использоваться
для проверки фактического типа экземпляра.
Например:
IF TypeOf(Self) = TypeOf(TPerson) THEN ...;
Слайд 18Таблица динамических методов.
Таблица виртуальных методов объектного типа содержит для каждого
описанного в объектном типе виртуального метода и его предков четырехбайтовую
запись.
Когда в порождающих типах определяется большое число виртуальных методов, в процессе создания производных типов может использоваться достаточно большой объем памяти, особенно если создается много производных типов.
Хотя в производных типах могут переопределяться только некоторые из наследуемых методов, таблица виртуальных методов каждого производного типа содержит указатели метода для всех наследуемых виртуальных методов,
даже если они не изменялись.
Слайд 19Таблица динамических методов.
Динамические методы обеспечивают в таких ситуациях альтернативу.
Для динамических
методов вводится новый формат таблицы методов и новый способ обработки
вызовов методов с поздним связыванием.
Вместо кодирования всех методов объектного типа с поздним связыванием в таблице динамических методов (ТДМ) кодируются только те методы, которые были в объектном типе переопределены.
Если в производных типах переопределяются только некоторые из большого числа методов с поздним связыванием, формат таблицы динамических методов использует меньшее пространство, чем формат таблицы виртуальных методов.
Слайд 20Таблица динамических методов.
Переопределим типы TStaff и Ттеасher следующим образом:
TStaff =
OBJECT(TPerson);
Bonus : REAL;
CONSTRUCTOR Init(Nm,Dt :STRING; Rt,Bn :REAL);
DESTRUCTOR Done;
VIRTUAL;
FUNCTION GetSum : REAL; VIRTUAL 10;
PROCEDURE ShowSum; VIRTUAL 20;
PROCEDURE ShowAll; VIRTUAL 30;
end;
TTeacher = OBJECT(TStaff)
Hours : WORD;
HourRate : REAL;
CONSTRUCTOR Init(Nm,Dt :STRING; Rt,Bn,Hrt :REAL; Hr :WORD);
DESTRUCTOR Done; VIRTUAL;
FUNCTION GetSum:REAL; VIRTUAL 10;
PROCEDURE ShowAll; VIRTUAL 30;
END;
Слайд 21Схемы таблиц виртуальных и динамических методов для TStaff
TBM TStaff
4
-4
Смещение
ТДМ TStaff
0
TStaff.Done
ТДМ TStaff
0
Кэшируемый индекс
Кэшируемое смещение
3
10
20
30
TStaff.GetSum
TStaff.ShowSum
TStaff.ShowAll
одно слово памяти
два слова памяти
Слайд 22Схемы таблиц виртуальных и динамических методов для ТТеаcher
TBM TTeacher
4
-4
Смещение ТДМ
TTeacher
0
TTeacher.Done
ТДМ TTeacher
Смещение ТДМ TStaff
Кэшируемый индекс
Кэшируемое смещение
2
10
30
TTeacher.GetSum
TTeacher.ShowAll
одно слово памяти
два слова
памяти
Слайд 23Таблица динамических методов.
Первое слово
Содержит смещение в сегменте данных родительской таблицы
динамических методов или 0, если родительская таблица динамических методов отсутствует.
Второе
и третье слова
Используются в кэш-буфере просмотра динамических методов и будут рассмотрены далее.
Четвертое слово
Содержит счетчик числа записей таблицы динамических методов.
Непосредственно за ним следует список слов, каждое из которых содержит индекс динамического метода, а затем список соответствующих указателей методов.
Длина каждого списка задается счетчиком числа записей ТДМ.
Слайд 24Таблица динамических методов.
Объектный тип имеет таблицу динамических методов только, если
в нем вводятся или переопределяются динамические методы.
Если объектный тип наследует
динамические методы, но они не переопределяются, и новые динамические методы не вводятся, то он просто наследует таблицу динамических методов своего предка.
Как и в случае таблицы виртуальных методов, таблица динамических методов записывается в инициализированную часть сегмента данных прикладной программы.
Слайд 25Вызов статических методов.
Статические методы используют те же соглашения о вызовах,
что и обычные процедуры и функции,
за исключением того, что
каждый метод имеет неявный дополнительный параметр Self, который соответствует параметру-переменной того же типа, что и объектный тип данного метода.
Параметр Self всегда передается последним и имеет вид 32-разрядного указателя на экземпляр, из которого вызывается метод.
Слайд 26Вызов статических методов.
Например:
в типе Tperson определим процедуру ShowName
введем переменную Person
типа ^TPerson,
Теперь вызов Person^.ShowName будет кодироваться следующим образом:
les DI,
Person; {загрузить Person в ES:DI}
push ES; {передать как параметр Self}
push DI;
call TPerson.ShowName; {непосредственный вызов ShowName}
Слайд 27Вызов статических методов.
При возврате метод должен удалить параметр Self из
стека точно так же, как он удаляет обычные параметры.
Методы всегда
используют дальний тип вызова, независимо от состояния директивы $F компилятора.
Слайд 28Вызов виртуальных методов.
Для вызова виртуального метода компилятор генерирует код, который:
выбирает
адрес таблицы виртуальных методов из поля таблицы виртуальных методов объекта,
вызывает метод, используя связанную с ним точку входа.
Например, для переменной Staff типа PStaff вызов Staff.GetSum будет генерировать следующий код:
les DI, Staff; {загрузить Staff в ES:DI}
push ES; {передать как параметр Self}
push DI;
mov DI,ES:[DI+6]; {извлечь смещение ТВМ из поля ТВМ}
call DWORD PTR [DI+12]; {вызвать запись ТВМ для GetSum}
Слайд 29Вызов виртуальных методов.
Правила совместимости для объектных типов позволяют Staff указывать
на TStaff и на ТТеасher или на любых других потомков
TStaff.
Если просмотреть приведенные ранее таблицы виртуальных методов TStaff и ТТеасher, можно увидеть, что для типа TStaff точка входа со смещением 12 в таблице виртуальных методов указывает на TStaff.GetSum.
Таким образом, в зависимости от фактического типа Staff во время вызова инструкция CALL вызывает либо TStaff.GetSum, либо ТТеасher.GetSum, либо метод любого другого потомка TStaff.
Слайд 30Вызов динамических методов.
Обработка вызова динамического метода более сложная и требует
больше времени, чем вызов виртуального метода
Вместо использования инструкции CALL для
вызова через указатель метода по статическому смещению в ТВМ, таблица динамических методов объектного типа и таблица динамических методов его предка должны просматриваться в поиске "самого верхнего" вхождения индекса конкретного динамического метода, а вызов затем должен выполняться через соответствующий указатель метода.
Этот процесс требует использования значительно большего числа инструкций, которые можно записать как встроенные (INLINE), поэтому Турбо Паскаль содержит подпрограмму обработки вызовов, используемую при вызове динамического метода.
Слайд 31Вызов динамических методов.
Если бы метод GetSum типа TStaff описывался как
динамический метод с индексом 10, то вызов Staff^.Getsum, где Staff
имеет тип PStaff, привел бы к генерации следующего кода:
les DI,Staff; {загрузить Staff в ED:DI}
push ES; {передать как параметр Self}
push DI;
mov DI,ES:[di+6];
{извлечь смещение ТДМ из поля ТВМ}
mov AX,10;
{загрузить в АХ индекс динамического метода}
call Dispatch;
{вызов подпрограммы обработки вызовов}
Слайд 34Вызов динамических методов.
Несмотря на использование кэширования и хорошо оптимизированной подпрограммы
обработки вызовов,
обработка вызова динамического метода может потребовать значительно больше
времени, чем вызов виртуального метода.
Однако в тех случаях, когда сами действия, выполняемые динамическим методом, требуют много времени, дополнительное пространство, сохраняемое таблицами динамических методов, может оказаться более существенным.
Слайд 35Вызов конструкторов и деструкторов.
Конструкторы и деструкторы используют те же соглашения
о вызовах, что и обычные методы, за исключением того, что
дополнительный параметр размером в слово, называемый параметром ТВМ, передается через стек непосредственно перед параметром Self.
Для конструкторов параметр ТВМ содержит смещение таблицы виртуальных методов для запоминания в поле таблицы виртуальных методов параметра Self, чтобы его инициализировать.
Слайд 36Вызов конструкторов и деструкторов.
Если конструктор вызывается для размещения динамического объекта
с помощью расширенного синтаксиса стандартной процедуры New, через параметр Self
передается указатель NIL.
Это заставляет конструктор размещать новый динамический объект, адрес которого передается вызывающей программе через DX:AX при возврате из конструктора.
Если конструктор не может разместить объект, то в DX:АХ возвращается пустой указатель NIL.
Слайд 37Вызов конструкторов и деструкторов.
Если конструктор вызывается с использованием собственного идентификатора
метода
(т.е. идентификатора типа объекта, за которым следуют точка и
идентификатор метода),
то в параметре таблицы виртуальных методов передается нулевое значение.
Это является указанием конструктору на то, что ему не следует инициализировать поле Self таблицы виртуальных методов.
Слайд 38Вызов конструкторов и деструкторов.
Для деструкторов нулевое значение параметра таблицы виртуальных
методов означает обычный вызов, а ненулевое указывает, что деструктор был
вызван с использованием расширенного синтаксиса стандартной процедуры Dispose.
Это заставляет деструктор удалить Self непосредственно перед возвратом.
Размер Self определяется из первого слова Self в ТВМ.