Понятие интерфейса и его назначение в Delphi


Объектный интерфейс или просто интерфейс — определяет методы, которые могут быть реализованы классом. Интерфейсы объявляются подобно классам, но не могут использоваться непосредственно и не имеют собственных реализаций методов, поскольку это обязанность любого класса, который поддерживает интерфейс — обеспечить реализации методов интерфейса. Интерфейс, подобно классу, также наследует методы всех своих предков. Переменная типа интерфейс может ссылаться на объекты, которые определяют этот интерфейс, однако, используя эту переменную, можно вызывать только методы, объявленные в этом интерфейсе.

Объявление интерфейса
Объявление интерфейса может включать указание интерфейса предка. Если никакой предок не определен, то объявляемый интерфейс — прямой потомок от интерфейса IUnknown, определенного в модуле System Delphi и являющегося общим предком всех интерфейсов.

Синтаксис объявление типа интерфейса имеет следующий вид:

Туре
<имя интерфейса>=Interface[(<имя родительского интерфейса>)]
[‘{GUID}’] // Global Unique IDentifier
<определение интерфейса> // Объявление методов и свойств
End;

• Интерфейсы, подобно классам, могут быть объявлены только в программе или модуле, но не в процедуре или функции, т.е. они глобальны.

• Объявление интерфейса может включать только методы и свойства (поля не предусмотрены). Таким образом, интерфейс — это просто описание связанных свойств и методов без реализации. Команды объявления разделов видимости в интерфейсе не разрешены. Все элементы интерфейса объявляются как в разделе Public класса, поэтому они видны всюду, где виден сам интерфейс.

• Интерфейсы не имеют никаких конструкторов или деструкторов. Они не могут быть использованы иначе, чем через классы, которые реализуют их методы.

• Методы не могут быть объявлены с директивами Virtual, Dynamic, Abstract, или Override. Так как интерфейсы не реализуют собственных методов, эти обозначения не имеют никакого значения.

• Все объявляемые в интерфейсе методы являются виртуальными и абстрактными. Таким образом, фактически Interface объявляет описание виртуальной таблицы методов, аналогичной VMT.

• Так как интерфейс не может иметь полей, команды свойств Read и Write должны обращаться только к методам. Команды хранения свойств не разрешены, но свойство-массив может быть объявлено как Default.

• Объявление интерфейса обычно включает глобальный уникальный идентификатор GUID, представляемый строковым литералом, заключенным в скобки, и предшествующий списку определений интерфейса. Для интерфейсов его называют IID (Interface IDentifier). Объявление GUID должно иметь вид:

[‘ {xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx}’]

Где каждый х — шестнадцатеричная цифра (0 до 9 или от А до F).
GUID — 16-байтовое двоичное значение, которое уникально идентифицирует интерфейс, компонентный класс или объект.
• Могут быть объявлены типизированные константы типа TGUID:

Const IIDJMALLOC: TGUID='{00000002-0000-0000-C000-000000000046}’;

Type IMalloc=Interface(IUnknown)
[‘ {00000002-0000-0000-COOO-000000000046}’]
Function AUoc(Size: Integer): Pointer; stdcall;
Function ReAlloc(P: Pointer; Size: Integer): Pointer; stdcall;
End;

Интерфейс IUnknown объявлен в блоке System Delphi так:

IUnknown=Interface
[‘{00000000-0000-0000-СООО-000000000046}’]
Function QueryInterface(Const IID: TGUID; Out Obj): HResult; stdcall;
Function _AddRef: Integer; stdcall;
Function _Release: Integer; stdcall;
End;

Фактически, для превращения обычного объекта OP в СОМ-объект необходимо реализовать интерфейс IUnknown, определив три стандартных метода СОМ:
• Querylnterface позволяет запрашивать (вызывать) интерфейсы объектов после получения указателя на объект-сервер. Клиент с помощью этого метода передает объекту-серверу в виде параметра IID нужного интерфейса. Если объект-сервер поддерживает этот интерфейс, то он возвращает указатель на него в параметре Obj (иначе возвращается Nil). При этом сама функция при положительном результате возвращает 0 и константу E_NOINTERFACE в противном случае. После получения указателя клиент может вызывать методы этого интерфейса.

Intf:=TNewClass.Create As IMalloc; // Пусть TNewClass реализует INewMalloc
Intf.QueryInterface(INewMalloc, Newlntf);
If Assigned(NewIntf) Then Labell.Caption:=NewIntf.Name;

Можно и другим путем проверить поддержку нужного интерфейса:
• _AddRef и _Release обеспечивают работу механизма учета ссылок интерфейса. Поскольку объект-сервер может быть затребован несколькими клиентами, то с помощью этих методов подсчитывается число подключившихся и отключившихся клиентов. Когда число ссылок (или подключившихся клиентов) становится равным нулю, объект-сервер уничтожает сам себя. Фактически интерфейс IUnknown — это механизм, который использует технология СОМ для подсчета числа ссылок и управления жизнью объекта.

Самый простой способ реализовать эти методы в классе состоит в том, чтобы наследовать реализацию класса TInterfacedObject из модуля System. Он может использоваться в программах, не экспортирующих СОМ-объекты.

Класс TInterfacedObject реализует интерфейс IUnknown. Поэтому TlnterfacedObject объявляет и реализует каждый из трех методов интерфейса IUnknown.

Соглашение о Вызовах:
Используемое по умолчанию в Delphi соглашение о вызовах — это register . Для связывания модулей, особенно, если они написаны на разных языках, необходимо объявлять все методы интерфейсов, используемых в СОМ, с stdcall. Следует использовать safecall, чтобы выполнить методы двойных (Dual) интерфейсов или интерфейсов CORBA.

Возможны директивы: register, pascal, cdecl, stdcall, safecall. Первые две означают передачу параметров слева направо в подпрограммы, а остальные наоборот. Все, кроме cdecl удаляют параметры из стека после возврата. Stdcall и safecall используются при обращении к функциям Windows API.

Предописание
Объявление интерфейса может заканчиваться зарезервированным словом Interface и точкой с запятой, т.е. без указания предка, GUID, или/и списка объявлений интерфейса. Такое объявление называется предописанием и аналогично директиве Forward в Паскале. Однако между предописанием и последующими объявлениями не может быть ничего другого, кроме объявлений типа. Предописания позволяют объявлять взаимно зависимые интерфейсы.

Туре
IControNInterface;
IWindow=Interface
[‘ {00000115-0000-0000-СООО-000000000044}’]
Function GetControI(Index: Integer): IControI;
End;
IControl=Interface
[‘{OOOOOHS-OOOO-OOOO-COOO-000000000049}’]
Function GetWindow: IWindow;
End;

Однако взаимно ссылающиеся друг на друга интерфейсы не допускаются. Например, нельзя получить IWindow из IControI и также получить IControl из IWindow.

Поддержка интерфейсов в Delphi
Интерфейсы в Delphi реализуются через классы. Для поддержки интерфейсов в ряде классов Delphi включены дополнительные методы.
• В классе TObject определены методы:
• Class Function GetlnterfaceTable: PInterfaceTable; — Возвращает указатель на таблицу интерфейсов.

Таким образом, таблица интерфейсов состоит из четырех колонок, наиболее важными из которых являются две первых. Первая колонка каждой строки таблицы содержит идентификатор интерфейса (IID), вторая — указатель на VMT таблицу конкретного интерфейса (VTable).
Указатель на таблицу виртуальных методов можно получить и из VMT таблицы класса. Указатель со смещением — 72 (vmtlntfTable) указывает на начальный адрес этой таблицы. Фактически таблица методов интерфейса располагается вслед за таблицей VMT класса и начинается она с методов Querylnterface, _AddRef и _Release. Далее следуют остальные методы интерфейсов, причем последний примыкает к VMT.

• GetInterface(Const IID: TGUID; Out Obj): Boolean; — Возвращает через параметр Obj указатель на интерфейс, если он поддерживается. Фактически возвращает указатель на VTable таблицу интерфейса.

Метод Getlnterface просматривает первую колонку таблицы интерфейсов, сверяя ее содержимое с заданным IID интерфейса. Если соответствие найдено, то параметр Obj возвращает указатель на VTable таблицу интерфейса. В противном случае он возвращает Nil. Функция возвращает True|False.

• На уровне класса TComponent реализована поддержка интерфейса IUnknown — определены методы _AddRef, _Release и Querylnterface. Таким образом, любой компонент Delphi поддерживает интерфейс IUnknown.


Комментарии запрещены.




Статистика