Реферат Курсовая Конспект
Общие представления об интерфейсах в Object PASCAL - раздел Программирование, Объектно-ориентированное программирование Интерфейс Объекта Определяют Методы И Свойства, Которые Могут Быть Реализован...
|
Интерфейс объекта определяют методы и свойства, которые могут быть реализованы классом-наследником этого интерфейса. Они описываются аналогично абстрактным классам, так же, как абстрактные классы, но в отличие от них, не могут иметь экземпляров, не могут иметь реализации никаких своих методов (в Object PASCAL допускается реализация части методов в абстрактные классы). Реализация методов интерфейсов осуществляется в классе, поддерживающем (наследующем) данный интерфейс. Переменная типа интерфейс - это ссылка. Она дает возможность ссылаться на объект, чей класс реализует данный интерфейс. Однако с помощью такой переменной разрешается вызывать только методы, декларированные в данном интерфейсе, а не любые методы данного объекта. Интерфейсы являются альтернативой множественному наследованию, имеют практически все его достоинства и лишены его недостатков. Их использование существенно для написания ПО для распределенных систем на основе COM (the Component Object Model) и CORBA (Common Object Request Broker Architecture). Объекты, поддерживающие интерфейсы, могут взаимодействовать с COM- объектами, написанными на C++ или Java.
Интерфейсы, как и классы, могут быть описаны только в самой наружной области видимости программы или модуля, но не в процедуре или функции. Описание типа для интерфейса имеет вид:
type
interfaceName =
interface (ancestorInterface)
['{GUID}']
список полей
end;
Отличия от классов:
· Не бывает экземпляров, реализующих тип интерфейс.
· Список полей интерфейса может включать только свойства и методы. Поля данных использовать нельзя. Соответственно, спецификаторы read и write должны быть методами.
· Все поля интерфейса всегда имеют тип видимости public (без явного указания); не разрешено использовать спецификаторов видимости (но у массивов может быть использован спецификатор default).
· Не бывает конструкторов и деструкторов.
· Методы не могут быть специфицированы как виртуальные, динамические, перекрытые, абстрактные. Поскольку они не имеют реализации в экземплярах типа, эти различия не имеют значения.
· Наследование через интерфейсы множественное.
· Реализация интерфейса может быть только в классе, при этом он должен реализовать все методы интерфейса (а значит, и все свойства)
Интерфейс, как и класс, наследует все методы прародителя, однако только на уровне абстракций, без реализации методов. Однако интерфейс наследует право реализации этих методов в классе, поддерживающем этот интерфейс. В декларации интерфейса можно указать, что интерфейс наследуется от прародительского интерфейса. Если такого указания нет, то интерфейс является непосредственным потомком IUnknown, который определен в модуле System и является прародителем для всех интерфейсов. В IUnknown продекларировано 3 метода — QueryInterface, _AddRef, Release. QueryInterface предназначен для поддержки интерфейсов объектов. _AddRef, _Release обеспечивают управление ссылками на интерфейсы. Простейший путь реализовать эти методы — создать класс-наследник от tInterfacedObject , описанного в модуле System.
Пример описания интерфейса:
type
IMalloc =
interface(IUnknown)
['{00000002-0000-0000-C000-000000000046}']
function Alloc(Size: Integer): Pointer; stdcall;
functionRealloc(P:Pointer;Size:Integer):Pointer;stdcall;
procedure Free(P: Pointer); stdcall;
function GetSize(P: Pointer): Integer; stdcall;
function DidAlloc(P: Pointer): Integer; stdcall;
procedure HeapMinimize; stdcall;
end;
Перед использованием продекларированного интерфейса он должен быть реализован в классе. Реализация осуществляется с помощью декларации в списке прародителей класса:
type
className =
class (ancestorClass,interface1,...,interfaceN)
memberList
end;
Например,
type
TMemoryManager =
class(TInterfacedObject, IMalloc, IErrorInfo)
...
end;
Когда класс реализует интерфейс, он должен реализовать (или наследовать реализацию) каждого метода, декларированного в интерфейсе. Ниже приведено описание tInterfacedObject из модуля System:
type
TInterfacedObject =
class(TObject, IUnknown)
protected
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
property RefCount: Integer read FRefCount;
end;
tInterfacedObject реализует интерфейс. Поэтому в нем описаны и реализованы все три метода IUnknown. Классы, реализующие интерфейсы, могут быть использованы как прародители. Класс tInterfacedObject реализует три метода интерфейса IUnknown и поэтому удобен как прародитель для всех классов, реализующих интерфейсы. Когда интерфейс реализован в классе, каждый из его методов реализован соответствующим методом (по умолчанию с тем же именем) и с такой же сигнатурой.
В классе-наследнике можно перекрыть методы реализуемого интерфейса. При этом соответствующий метод должен быть виртуальным или динамическим). Также возможно заново унаследовать интерфейс:
type
IWindow =
interface
['{00000115-0000-0000-C000-000000000146}']
procedure Draw;
...
end;
TWindow =
class(TInterfacedObject, IWindow) //TWindow реализует IWindow
procedure Draw;
...
end;
TFrameWindow =
class(TWindow, IWindow) //TFrameWindow переопределяет реализацию Iwindow
procedure Draw;
...
end;
При этом в классе все методы от прародительской реализации этого интерфейса запираются (не наследуются), в том числе выражения различения методов.
6.2. Реализация интерфейсов свойством
Директива implements в описании свойства класса позволяет делегировать реализацию интерфейса свойству в реализуемом классе. Например, свойство
property MyInterface: IMyInterface
read FMyInterface
implements IMyInterface;
описывает свойство, реализующее интерфейс ImyInterface. Директива implements должна быть последней в описании свойства и может иметь перечисление после нее имен нескольких интерфейсов, разделенных запятыми. Делегируемое свойство:
· может иметь тип класса или интерфейса.
· не может быть массивом или иметь спецификатор индекса.
· должно иметь спецификатор read; если имеется метод “read”, он не может быть динамическим (хотя может быть виртуальным) или описывать директиву message.
· Если свойство типа интерфейс, соответствующий интерфейс или его интерфейс-прародитель должен присутствовать в списке интерфейсов класса, где продекларировано свойство.
Делегируемое свойство должно возвращать объект, чей класс полностью реализует интерфейс, без использования выражений различия методов (“мэппинга”), см. далее. Например:
type
IMyInterface =
interface
procedure P1;
procedure P2;
end;
TMyClass =
class(TObject, IMyInterface)
FMyInterface: IMyInterface;
property MyInterface: IMyInterface
read FMyInterface
implements IMyInterface;
end;
tatherClass=
class(tany,ImyInterface)
…
end;
var
aMyClass: TMyClass;
aOtherClass:tOtherClass;
aMyInterface: IMyInterface;
begin
aMyClass := TMyClass.Create;
aMyClass.FMyInterface := ... // объект, чей класс реализует ImyInterface
aMyInterfase:=aMyClass.myInterfase// ссылка на тот же объект
aMyInterface := MyClass;// допустимо, так как ImyInteface – интерфейс-прародитель для tMyClass; ссылка на объект,агрегирующий
aMyInterface.MyInterface:=totherClass.create;//это второй объект
aMyInterface.P1;
aMyInterfase.MyInterfase.P1;//это вызов методаP1 для второго объекта
end;
6.3. Различение имен при реализации нескольких интерфейсов
Когда класс реализует два или более интерфейсов, имеющих методы с одинаковыми именами, для разрешения конфликта имен используют выражения различения методов в виде “мэппинга”:
procedure interface.interfaceMethod = implementingMethod;
или
function interface.interfaceMethod = implementingMethod;
где implementingMethod — это метод, определенный в классе, или одном из его прародителей. Он может быть методом, описанном далее в описании класса, но не может быть “private” методом класса или одного из его прародителей, описанном в другом модуле. Пример:
type
TMemoryManager = class(TInterfacedObject, IMalloc, IErrorInfo)
function IMalloc.Alloc = Allocate;
procedure IMalloc.Free = Deallocate;
...
end;
Выражения различения методов не могут использовать мэппинг, имеющийся в классах-прародителях.
В спецификации интерфейса может быть описан уникальный глобальный идентификатор — globally unique identifier (GUID), представленный в виде строки литералов, заключенной в скобки:
['{xxxxxxxx–xxxx–xxxx–xxxx–xxxxxxxxxxxx}']
где каждый X это 16-ричная цифра ( от 0 до F). GUID — это 16-байтовое двоичное число, уникально идентифицирующее интерфейс.
Если у интерфейса есть GUID, можно его использовать для запросов к переменной интерфейса, получить ссылки на его реализации. Типы tGUID и pGUID, определенные в модуле System, используются для работы с переменными типа GUID и указателями на такие переменные. Их описание следующее:
type
pGUID = ^tGUID;
tGUID =
record
D1: Longword;
D2: Word;
D3: Word;
D4: array[0..7] of Byte;
end;
Можно описать типизированную константу типа TGUID, например, имеющую имя IID -IMalloc:
const IID_IMalloc: TGUID = '{00000002-0000-0000-C000-000000000046}';
Вызов в процедуре переменной типа GUID аналогичен соответствующему типу interfase. Может быть использовано как значение, так и постоянный параметр типа TGUID. Например:
function Supports(Unknown: IUnknown; const IID: TGUID): Boolean;
Таким образом, вызов Supports может быть сделан одним из двух путей:
if Supports(Allocator, IMalloc) then ...
или
if Supports(Allocator, IID_IMalloc) then ...
5.11. Спецификаторы вызовов процедур и функций
При задании процедуры или функции можно использовать спецификаторы вызова register, pascal, cdecl, stdcall, safecall. Например:
function MyFunction(X, Y: Real): Real; cdecl;
Эти спецификаторы влияют на особенности передачи параметров в процедуру, а также на работу со стеком, использование регистров, и обработку исключительных ситуаций. По умолчанию спецификатор считается register.
Директива | Передача параметров | Очищает стек | Передает параметры | Вызовы |
Register | слева направо | программа | через регистры | по умолчанию, наиболее эфф. |
Pascal | слева направо | программа | через стек | обратно совместимо с Turbo PASCAL |
cdecl | справа налево | вызывающий | через стек | DLL,написанные на C или C++ |
stdcall | справа налево | программа | через стек | Windows API |
safecall | справа налево | программа | через стек | Объекты COM; методы парных интерфейсов |
5.12. Динамические массивы
Было:
var
A: array[1..100] of string;
B: array[1..10] of array [1..20] of integer;
Стало можно:
var
A: array of string;
B: array of array of integer;
Декларация динамического массива (переменных A и B) не выделяет под них памяти. Память выделяется процедурой SetLength:
SetLength(A,100);
SetLength(B,10,20);
Индексация динамических массивов всегда идет от нуля.
Для освобождения памяти из-под динамического массива:
а) либо присвоить nil переменной:
A:=nil;
B:=nil;
б) либо — вызвать процедуру Finalize:
Finalize(A);
Finalize(B);
Пример:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Label1: TLabel;
Label2: TLabel;
Button3: TButton;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
A: array of string;
B: array of array of integer;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
close
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
SetLength(A,100);
SetLength(B,10,20);
Label1.caption:='Память выделена';
end;
procedure TForm1.Button3Click(Sender: TObject);
var s:string;
begin
A[99]:='Ok';
B[9,19]:=7;
Label3.caption:=A[99];
str(B[9,19],s);
Label5.caption:=s;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
A:=nil;
Finalize(B);
Label1.caption:='Память освобождена';
end;
end.
5.13. Перезагрузка (overloading) методов, процедур и функций
Разрешено использование одинаковых имен, но с разными сигнатурами аргументов (числом или типом аргументов):
Constructor create(aOwner:tComponent);overload;override;
Constructor create(aOwner:tComponent;Text:String);overload;
Но нельзя иметь одинаковое число и типы аргументов, хоть и с разными именами. Например, нельзя добавить третий вариант:
Constructor create(aOwner:tComponent;Name:String);overload;
Пример для функций:
function Divide(x,y:real):Real;overload;
begin
Result:=x/y;
end;
function Divide(x,y:integer):Integer;overload;
begin
Result:=x div y;
end;
5.14. Параметры по умолчанию
Описываются аналогично константам в предыдущих версиях:
Name: Type=value;
При вызове параметры по умолчанию могут быть опущены. Например, если взять заголовок процедуры заполнения массива числом, передаваемым в качестве параметра:
Procedure FillArray(A:array of integer;V:integer=1);
Тогда вызов этой процедуры можно производить так:
FillArray(myArray,1);
Либо, что то же,
FillArray(myArray);
Будьте осторожны и не используйте вызовы overloaded процедур с опущенными значениями по умолчанию, когда число и тип параметров совпадают с одной из других overloaded процедур.
– Конец работы –
Эта тема принадлежит разделу:
На сайте allrefs.net читайте: "Объектно-ориентированное программирование"
Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Общие представления об интерфейсах в Object PASCAL
Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:
Твитнуть |
Новости и инфо для студентов