Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / Pascal и Delphi / Иллюстрированный самоучитель по Delphi 6 / Часть II . Язык Object Pascal / Классы и интерфейсы /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Интерфейсы - Программирование от RIN.RU
Интерфейсы

Интерфейсы играют главную роль в технологиях СОМ (Component Object Model - компонентная модель объектов), CORBA (Common Object Request Broker Architecture - архитектура с брокером требуемых общих объектов) и связанных с ними технологиях удаленного доступа, т. е. технологиях доступа к объектам, расположенным (и выполняющимся) на другой машине. Их основная задача - описать свойства, методы и события удаленного объекта в терминах машины клиента, т. е. на используемом при разработке клиентского приложения языке программирования. С помощью интерфейсов программа клиента обращается к удаленному объекту так, как если бы он был ее собственным объектом.


Тема интерфейсов достаточно обширна и интересна. В этой главе даются лишь самые общие сведения об интерфейсах. Сведение этой темы в одну главу с классами не случайно, т. к. интерфейс представляет собой пустой класс, т. е. класс, в котором провозглашены, но никак не расшифрованы свойства и методы.


Создание и использование интерфейса


Интерфейсы представляют собой частный случай описания типов. Они объявляются с помощью зарезервированного слова interface. Например:


type
IEdit = interface
procedure Copy; stdcall;
procedure Cut; stdcall;
procedure Paste; stdcall;
function Undo: Boolean; stdcall;
end;


Такое объявление эквивалентно описанию абстрактного класса в том смысле, что провозглашение интерфейса не требует расшифровки объявленных в нем свойств и методов.


В отличие от классов интерфейс не может содержать поля, и, следовательно, объявляемые в нем свойства в разделах read и write могут ссылаться только на методы. Все объявляемые в интерфейсе члены размещаются в единственной секции public. Методы не могут быть абстрактными (abstract), виртуальными (virtual), динамическими (dynamic) или перекрываемыми (override). Интерфейсы не могут иметь конструкторов или деструкторов, т. к. описываемые в них методы реализуются только в рамках поддерживающих их классов, которые называются интерфейсными.


Если какой-либо класс поддерживает интерфейс (т. е. является интерфейсным), имя этого интерфейса указывается при объявлении класса в списке его родителей:


TEditor = class(TInterfacedObject,IEdit)
procedure Copy; stdcall;
procedure Cut; stdcall;
procedure Paste; stdcall;
function Undo: Boolean; stdcall;
end;


В отличие от обычного класса интерфейсный класс может иметь более одного родительского интерфейса:


type
IMylnterface = interface procedure Delete; stdcall;
end;


TMyEditor = class(TInterfacedObiect, lEdit, IMylnterface)
procedure Copy; stdcall;
procedure Cut; stdcall;
procedure Paste; stdcall;
function Undo:, Boolean; stdcall;
procedure Delete; stdcall;
end;


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


IPaint = interface
procedure CirclePaint(Canva: TCanvas; X,Y,R: Integer);
procedure RectPaint(Canva: TCanvas; X1,Y1,X2,Y2: Integer);
end;


и использующий его интерфейсный класс


TPainter = class(TInterfacedObject,IPaint)
procedure CirclePaint(Canva: TCanvas; X,Y,R: Integers);
procedure RectPaint(Canva: TCanvas; X1,Y1,X2,Y2: Integer);
end;


то в разделе implementation следует указать реализацию методов:


procedure TPainter.CirclePaint(Canva: TCanvas; X,Y,R: Integers; )
begin
with Canva do
Ellipse(X, Y, X+2*R, Y+2*R) ;
end;


procedure TPainter.RectPaint(Canva: TCanvas; X1,Y1,X2,Y2: Integer);
begin
with Canva do
Rectangle(XI, Yl, X2, Y2)
end;


Теперь можно объявить интерфейсный, объект класса TPainter, чтобы с его помощью нарисовать окружность и квадрат:


procedure TForm1.PaintBoxIPaint(Sender: TObject);
var
Painter: IPaint;
begin
Painter := TPainter.Create;
Painter.CirclePaint(PaintBoxl.Canvas,10,0,10) ;
Painter.RectPaint(PaintBoxl.Canvas,40,0,60,20);
end;


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


type
TPainter = class(TInterfacedObject, IPaint)
end;


было бы ошибкой: компилятор потребовал бы вставить описание методов CirclePaint и RectPaint.


Подобно тому как все классы в Object Pascal порождены от единственного родителя TObject, все интерфейсные классы порождены от общего предка TInterfacedObject. Этот предок умеет распределять память для интерфейсных объектов и использует глобальный интерфейс lunknow:


type
TInterfacedObject = class(TObject, lUnknown)


private
FRefCount: Integer;
protected
function Querylnterface(
const IID: TGUID; out Obj): Integer; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
property RefCount: Integer read FRefCount;
end;


Если бы в предыдущем примере класс TPainter был описан так:


TPainter = class(IPaint)
procedure CirclePaint(Canva: TCanvas; X,Y,R: Integer);
procedure RectPaint(Canva: TCanvas; X1,Y1,X2,Y2: Integer);
end;


компилятор потребовал бы описать недостающие методы Queryinterface, _Add И _Release класса TInterfacedObject. Поле FRef Count этого класса служит счетчиком вызовов интерфейсного объекта и используется по принятой в Windows схеме: при каждом обращении к методу Add интерфейса IUnknow счетчик наращивается на единицу, при каждом обращении к Release - на единицу сбрасывается. Когда значение этого поля становится равно 0, интерфейсный объект уничтожается и освобождается занимаемая им память.


Если интерфейс предполагаетсяиспользовать в технологиях COM/DCOM или CORBA, его методы должны описывать с директивой stdcall или (для объектов Автоматизации) safecall


К интерфейсному объекту можно применить оператор приведения типов as, чтобы использовать нужный интерфейс:


procedure PaintObjects(P: TInterfacedObject)


var
X: IPaint;
begin
try
X := P as IPaint;
X.CirclePaint(PaintBoxl.Canvas,0,0,20)
except
ShowMessage('Объект не поддерживает интерфейс IPaint')
end
end;


Встретив такое присваивание, компилятор создаст код, с помощью которого вызывается метод Queryinterface интерфейса IUnknow с требованием вернуть ссылку на интерфейс IPaint. Если объект не поддерживает указанный интерфейс, возникает исключительная ситуация.


Интерфейсы, рассчитанные на использование в удаленных объектах, должны снабжаться глобально-уникальным идентификатором (guiD). Например:


IPaint = interface
['{A4AFEB60-7705-11D2-8B41-444553540000}']
procedure CirclePaint(Canva: TCanvas; X,Y,R: Integer);
procedure RectPaint(Canva: TCanvas; Xl,Yl,X2,Y2: Integer);
end;


Глобально-уникальные идентификаторы создаются по специальной технологии, гарантирующей ничтожно малую вероятность того, что два guid совпадут. Эта технология включена в Windows 32: чтобы получить guid для вновь созданного интерфейса в среде Delphi, достаточно нажать клавиши Ctrl+Shift+G. Для работы с guid в модуле System объявлены следующие типы:


type
PGUID = ^TGUID;
TGUID = record Dl: LongWord;
D2: Word;
D3: Word;
D4: array [0..7] of Byte;
end;


Программист может объявлять типизированные константы типа tguid, например:


const IID_IPaint: TGUID= ['{A4AFEB61-7705-11D2-8B41-444553540000}'] ;


Константы guid могут использоваться вместо имен интерфейсов при вызове подпрограмм. Например, два следующих обращения идентичны:


procedure Paint(const IID: TGUID);
Paint(IPaint) ;
Paint(IID_Paint);


С помощью зарезервированного слова implements программист может делегировать какому-либо свойству некоторого класса полномочия интерфейса. Это свойство должно иметь тип интерфейса или класса. Если свойство имеет тип интерфейса, имя этого интерфейса должно указываться в списке родителей класса, как если бы это был интерфейсный класс:


type
IMylnterface = interface
procedure P1; procedure P2 ;
end;


TMyClass = class(TObject, IMylnterface)
FMyInterface: IMylnterface;
property Mylnterface: IMylnterface
read FMyInterface implements IMylnterface;
end;


Обратите внимание: в этом примере класс TMyciass не является интерфейсным, т. е. классом, в котором исполняются методы p1 и P2. Однако если из него убрать определение уполномоченного свойства Mylnterface, он станет интерфейсным, и в нем должны быть описаны методы интерфейса IMylnterface.


Уполномоченное свойство обязательно должно иметь часть read. Если оно имеет тип класса, класс, в котором оно объявлено, не может иметь других уполномоченных свойств.


Вперед  >>>
 1  2 


 8  Комментарии к статье  8 8  Обсудить в чате

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь