Читайте также:
|
|
Работа виртуальных методов основана на косвенном вызове подпрограмм. При косвенном вызове команда вызова подпрограммы оперирует не адресом подпрограммы, а адресом места в памяти, где хранится адрес подпрограммы. Вы уже сталкивались с косвенным вызовом при использовании процедурных переменных. Процедурная переменная и была тем местом в памяти, где хранился адрес вызываемой подпрограммы. Для каждого виртуального метода тоже создается процедурная переменная, но ее наличие и использование скрыто от программиста.
Все процедурные переменные с адресами виртуальных методов пронумерованы и хранятся в таблице, называемой таблицей виртуальных методов (VMT — от англ. Virtual Method Table). Такая таблица создается одна для каждого класса объектов, и все объекты этого класса хранят на нее ссылку.
Структура объекта в оперативной памяти:
В таблице виртуальных методов хранятся адреса всех виртуальных методов класса, независимо от того, унаследованы ли они от предка или перекрыты в данном классе.
Вызов виртуального метода осуществляется следующим образом:
1) Через объектную переменную выполняется обращение к занятому объектом блоку памяти;
2) Далее из этого блока извлекается адрес таблицы виртуальных методов (он записан в четырех первых байтах);
3) На основании порядкового номера виртуального метода извлекается адрес соответствующей подпрограммы;
4) Вызывается код, находящийся по этому адресу.
Покажем, как можно реализовать косвенный вызов виртуального метода ParseLine (он имеет нулевой номер в таблице виртуальных методов) обычными средствами процедурного программирования:
type
TVMT = array[0..9999] of Pointer;
TParseLineFunc = function(Self: TTextReader; constLine: string): Integer;
var
Reader: TTextReader; // объектная переменная
ObjectDataPtr: Pointer; // указатель на занимаемый объектом блок памяти
VMTPtr: ^TVMT; // указатель на таблицу виртуальных методов
MethodPtr: Pointer; // указатель на метод
begin
...
ObjectDataPtr:= Pointer(Reader); // обращение к данным объекта
VMTPtr:= Pointer(ObjectDataPtr^); // извлечение адреса VMT
MethodPtr:= VMTPtr^[0]; // извлечение адреса метода из VMT
TParseLineFunc(MethodPtr)(Reader, S); // вызов метода
...
end.
Дата добавления: 2015-11-16; просмотров: 76 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Атрибуты доступа к элементам объектов | | | Абстрактный виртуальный метод |