Теперь, когда мы разобрались с основными определениями и механизмами ООП, настало время более подробно изучить, что представляет собой объект и как он работает. Ясно, что каждый экземпляр класса содержит отдельную копию всех его полей. Ясно, что где-то в его недрах есть указатели на таблицу виртуальных методов и таблицу динамических методов. А что еще там имеется? И как происходит вызов методов? Вернемся к примеру из разд. "Полиморфизм" данной главы:
type
TFirstClass = class
FMyFieldl: Integer;
FMyField2: Longint;
procedure StatMethod;
procedure VirtMethodl; virtual;
procedure VirtMethod2; virtual;
procedure DynaMethodl; dynamic;
procedure DynaMethod2; dynamic;
end;
TSecondClass = class(TMyObject)
procedure StatMethod;
procedure VirtMethodl;
override; procedure DynaMethodl;
override; end;
Objl: TFirstClass;
Obj2: TSecondClass;
На рис. 1.1 показано, как будет выглядеть внутренняя структура рассмотренных в нем объектов.
Первое поле каждого экземпляра того или иного объекта содержит указатель на его класс. Класс как структура состоит из двух частей. Начиная с адреса, на который ссылается указатель на класс, располагается таблица виртуальных методов. Напомним, что она содержит адреса всех виртуальных методов класса, включая унаследованные от предков. Длина таблиц VMT объектов Оbj1 и Obj2 одинакова— по два элемента (8 байт). Перед таблицей виртуальных методов расположена специальная структура, содержащая дополнительную служебную информацию. В ней содержатся данные, полностью характеризующие класс: его имя, размер экземпляра, указатели на класс-предок, имя класса и т. д. На рис. 1.1 она показана одним блоком, а ее содержимое расшифровано ниже.
Одно из полей структуры содержит адрес таблицы динамических методов класса (DMT). Таблица имеет следующий формат — в начале слово, содержащее количество элементов таблицы; затем — слова, соответствующие индексам методов. Нумерация индексов начинается с —1 и идет по убывающей. После индексов идут собственно адреса динамических методов. Обратите внимание, что DMT объекта Оbj1 состоит из двух элементов, Obj2 — из одного, соответствующего перекрытому методу DynaMethodl. В случае вызова Qbj2.DynaMethod2 индекс не будет найден в таблице DMT Obj2, и произойдет обращение к DMT Оbj1. Именно так экономится память при использовании динамических методов.