Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Механизм вызова метода объекта через интерфейсСодержание книги
Похожие статьи вашей тематики
Поиск на нашем сайте
Алгоритм вызова метода интерфейса такой же, как алгоритм вызова метода класса. Когда через интерфейсную переменную выполняется вызов метода, Intf. NextLine, реализуется следующий алгоритм: 1) из интерфейсной переменной извлекается адрес (по нему хранится адрес таблицы методов интерфейса); 2) по полученному адресу извлекается адрес таблицы методов интерфейса; 3) на основании порядкового номера метода в интерфейсе из таблицы извлекается адрес соответствующей подпрограммы; 4) вызывается код, находящийся по этому адресу. Этот код является переходником от метода интерфейса к методу объекта. Его задача – восстановить из ссылки на интерфейс значение указателя Self (путем вычитания заранее известного значения) и выполнить прямой переход на код метода класса.
Обычными средствами процедурного программирования этот алгоритм реализуется так: Type TMethodTable = array[0..9999] ofPointer; TNextLineFunc = function(Self: ITextReader): Boolean; Var Intf: ITextReader; // интерфейсная переменна IntfPtr: Pointer; // адрес внутри интерфейсной переменной TablePtr: ^TMethodTable; // указатель на таблицу методов интерфейса MethodPtr: Pointer; // указатель на метод Begin ... IntfPtr:= Pointer(Intf); // 1) извлечение адреса из интерфейсной Переменной TablePtr:= Pointer(IntfPtr^); // 2) извлечение адреса таблицы методов Интерфейса MethodPtr:= TablePtr^[3]; // 3) извлечение адреса нужного метода из таблицы TNextLineFunc(MethodPtr)(Intf); // 4) вызов метода через переходник ... End.
Вызов метода через интерфейс в машинном коде выполняется весьма эффективно (всего несколько инструкций процессора), поэтому в подавляющем большинстве случаев потерями на вызов можно пренебречь. Для доступа к объекту через интерфейс нужна интерфейсная переменная: Var Intf: ITextReader;
Интерфейсная переменная занимает в оперативной памяти четыре байта, хранит ссылку на интерфейс объекта и автоматически инициализируется значением nil. Перед использованием интерфейсную переменную инициализируют значением объектной переменной: Var Obj: TTextReader; // объектная переменная Intf: ITextReader; // интерфейсная переменная Begin ... Intf:= Obj; ... end; После инициализации интерфейсную переменную Intf можно использовать для вызова методов объекта Obj: Intf.Active:= True; // -> Obj.SetActive(True); Через интерфейсную переменную доступны только те методы и свойства объекта, которые есть в интерфейсе: Intf.Free; // Ошибка! У интерфейса ITextReadaer нет методаFree. Obj.Free; // Метод Free можно вызвать только так. Алгоритм вызова метода интерфейса такой же, как алгоритм вызова метода класса. Когда через интерфейсную переменную выполняется вызов метода, Intf.NextLine, реализуется следующий алгоритм: 1) из интерфейсной переменной извлекается адрес (по нему хранится адрес таблицы методов интерфейса); 2) по полученному адресу извлекается адрес таблицы методов интерфейса; 3) на основании порядкового номера метода в интерфейсе из таблицы извлекается адрес соответствующей подпрограммы; Вызывается код, находящийся по этому адресу. Этот код является переходником от метода интерфейса к методу объекта. Его задача – восстановить из ссылки на интерфейс значение указателя Self (путем вычитания заранее известного значения) и выполнить прямой переход на код метода класса.
Обычными средствами процедурного программирования этот алгоритм реализуется так: Type TMethodTable = array[0..9999] ofPointer; TNextLineFunc = function(Self: ITextReader): Boolean; Var Intf: ITextReader; // интерфейсная переменна IntfPtr: Pointer; // адрес внутри интерфейсной переменной TablePtr: ^TMethodTable; // указатель на таблицу методов интерфейса MethodPtr: Pointer; // указатель на метод Begin ... IntfPtr:= Pointer(Intf); // 1) извлечение адреса из интерфейсной Переменной TablePtr:= Pointer(IntfPtr^); // 2) извлечение адреса таблицы методов Интерфейса MethodPtr:= TablePtr^[3]; // 3) извлечение адреса нужного метода из таблицы TNextLineFunc(MethodPtr)(Intf); // 4) вызов метода через переходник ... End. Вызов метода через интерфейс в машинном коде выполняется весьма эффективно (всего несколько инструкций процессора), поэтому в подавляющем большинстве случаев потерями на вызов можно пренебречь. Алгоритм вызова метода интерфейса такой же, как алгоритм вызова метода класса. Когда через интерфейсную переменную выполняется вызов метода, Intf.NextLine, реализуется следующий алгоритм: 1) из интерфейсной переменной извлекается адрес (по нему хранится адрес таблицы методов интерфейса); 2) по полученному адресу извлекается адрес таблицы методов интерфейса; 3) на основании порядкового номера метода в интерфейсе из таблицы извлекается адрес соответствующей подпрограммы; Вызывается код, находящийся по этому адресу. Этот код является переходником от метода интерфейса к методу объекта. Его задача – восстановить из ссылки на интерфейс значение указателя Self (путем вычитания заранее известного значения) и выполнить прямой переход на код метода класса.
Один класс может содержать реализацию нескольких интерфейсов.
Применение интерфейса для доступа к объекту динамически-подключаемой библиотеки Если вы поместите свой класс в DLL-библиотеку, то при необходимости использовать его в главной программе столкнетесь с проблемой. Подключение модуля с классом к главной программе приведет к включению в нее кода всех методов класса, т.е. задача выделения класса в DLL-библиотеку не будет решена. Если же не подключить модуль с описанием класса, главная программа вообще не будет знать о существовании класса, и воспользоваться классом будет невозможно. Эта проблема решается с помощью интерфейсов. Сначала вынесем описание интерфейса ITextReader в отдельный модуль (например, ReaderIntf), чтобы этот модуль в дальнейшем можно было подключить к главной программе: unit ReadersIntf; Interface Type ITextReader = interface(IInterface) ... end; Implementation End. Затем удалим описание интерфейса из модуля ReadersUnit, а вместо него подключим модуль ReaderIntf:
unit ReadersUnit; Interface Uses ReaderIntf; ... Наконец включим скорректированный модуль ReadersUnit в DLL-библиотеку, которую назовем ReadersLib:
library ReadersLib; Uses SysUtils, Classes, ReadersUnit; {$R *.res} Begin End. Вроде бы все готово, и теперь в главной программе достаточно подключить модуль ReaderIntf и работать с объектами через интерфейс ITextReader.
А как в программе создавать объекты классов, находящихся в DLL-библиотеке? Ведь в нтерфейсе нет методов для создания объектов! Для этого определим в DLL-библиотеке специальную функцию и экспортируем ее:
Library ReadersLib; ... Function GetDelimitedReader(constFileName: string; constDelimiter: Char = ';'): ITextReader; Begin Result:= TDelimitedReader.Create(FileName, Delimiter); end; Exports GetDelimitedReader; Begin End.
В главной программе импортируйте функцию GetDelimitedReader, чтобы с ее помощью создавать объекты класса TDelimitedReader: Program Example; Uses ReadersIntf; function GetDelimitedReader(constFileName: string; constDelimiter: Char = ';'): ITextReader; external 'ReadersLib.dll' name 'GetDelimitedReader'; Var Intf: ITextReader; Begin Intf:= GetDelimitedReader; ... End.
|
||||
Последнее изменение этой страницы: 2016-08-14; просмотров: 478; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.147.52.243 (0.011 с.) |