Turbo Assembler 3.0. Руководство пользователя

         

Вызов виртуального метода


Любой вызов виртуального метода требует косвенного вызова процедуры метода. Для этого используйте расширенную инструкцию CALL.METHOD. Для выполнения вызова Турбо Ассемблер генерирует следующие инструкции:

1. Загружает промежуточные регистры указателем на ТВМ из эк- земпляра объекта.

2. Выполняет косвенный вызов соответствующего элемента таб- лицы.

Таким образом, когда вы задаете:

CALL <экземпляр> METHOD <объект>:<метод> USES <seg>:<reg> <вызов_проц>

то генерируются следующие инструкции:

MOV <рег>, [<экземпляр>.<указатель_ТВМ>] CALL [(<сегм><рег>).<метод>] <вызыв_проц>

Первая инструкция загружает выбранный регистр <рег> адресом таблицы виртуальных методов из поля указателя ТВМ структуры объ- екта. Вторая инструкция выполняет косвенный вызов соответствующе- го метода в таблице.

Например, вызов в виде:

CALL es:di method list:insert uses ds:bx pascal,es di,es dx,es cx

генерирует последовательность вида:

mov bx,[es:di.@Mptr_list] CALL [ds:bx.insert] pascal,es di,es dx,es cx

Заметим, для объектов, описанных с таблицами NEAR, инструк- цией CALL.METHOD будет загружаться только регистр смещения. Сегментный регистр всегда должен содержать корректное значение. В следующем примере показано, как обеспечить правильную установку сегментного регистра:

; Добавить узел к концу объекта связанного списка. ; Это виртуальный метод "list_append". list_append PROC PASCAL NEAR ARG @@list:dword,\ @@new:dword USES dx,bx, es,di mov ax,@Data mov ds,ax les di,@@list sub ax,ax CALL es:di method list:insert uses DS:bx pascal, es di,@@new,ax ax ret ENDP

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


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

node STRUC GLOBAL METHOD { construct:dword = node_construct ; подпрограмма ; конструктора узла destroy:dword = node_destroy ; подпрограмма ; деструктора узла init:dword = node_init ; подпрограмма ; инициализации узла deinit:dword = node_deinit ; подпрограмма ; деинициализации узла routine virtual next:word = node_adv ; подпрограмма ; следующего узла virtual prev:word = node_back ; подпрограмма ; предыдущего узла virtual print:word = node_print ; подпрограмма ; содержимого узла } node_next dd ? ; указатель следующего ; узла node_prev dd ? ; указатель ; предыдущего узла ends

Чтобы можно было использовать связанный список или очередь, вы можете определить любое число объектов, наследующих объект node. Приведем два примера:

mlabel STRUC GLOBAL node METHOD { virtual print:word = label_print } label_name db 80 dup (?) label_addr db 80*2 dup (?) label_city db 80 dup (?) label_state db 2 dup (?) label_zip db 10 dup (?) ENDS

book STRUC GLOBAL node METHOD { virtual print:word = book_print } book_title db 80 dup (?) book_author db 80 dup (?) ENDS

В следующем примере вы для объектов label и book вызываем методы путем вызова printit. Если "предком" является node, не важно, какой объект передается printit. Так как метод печати - это виртуальный метод, вызов выполняется косвенно через ТВМ объ- екта. При первом вызове printit, так как мы передаем экземпляр объекта label, вызывается процедура метода label_print. При вто- ром вызове printit вызывается процедура метода book_print, пос- кольку мы передаем экземпляр объекта book. Заметим, что если бы метод print был статическим, то при вызове node_print всегда вы- зывалась бы процедура node_print (что нежелательно).

call printit pascal,<<адрес экземпляра объекта label>> call printit pascal,<<адрес экземпляра объекта book>> . . . printit proc pascal near arg @@obj:dword uses ds,si,es,bx mov ax,@data mov es,ax lds si@@obj call ds:si method node:print uses es:bx pascal,ds si ret endp


Содержание раздела