Выбрать главу

type

IShape = interface

procedure Draw;

property X: integer read;

property Y: integer read;

end;

IBrush = interface

procedure Draw;

property Size: integer read;

end;

Brush = class(IShape,IBrush)

// метод Draw реализуется единожды

end;

Чтобы решить проблему с одинаковыми именами в интерфейсах, в .NET классы могут реализовывать методы интерфейсов так называемым явным образом, так что вызов метода интерфейса для переменной класса возможен только после явного приведения к типу интерфейса. В PascalABC.NET такие классы определять нельзя, однако, пользоваться такими классами, реализованными в .NET, можно. Например, тип integer явно реализует интерфейс IComparable:

var i: integer := 1;

var res : integer := IComparable(i).CompareTo(2);

// i.CompareTo(2) - ошибка компиляции

Обобщенные типы

Обобщенные типы: обзор

Обобщенным типом (generic) называется шаблон для создания класса, записи или интерфейса, параметризованный одним или несколькими типами. Класс (запись, интерфейс) образуется из шаблона класса (записи, интерфейса) подстановкой конкретных типов в качестве параметров. Параметры указываются после имени обобщенного типа в угловых скобках. Например, Stack<T> - шаблон класса списка элементов типа T, параметризованный типом T, а Stack<integer> - класс списка с элементами типа integer.

Обобщённые подпрограммы описываются здесь.

Для объявления шаблона класса используется следующий синтаксис:

type

Node<T> = class

data: T;

next: Node<T>;

public

constructor Create(d: T; nxt: Node<T>);

begin

data := d;

next := nxt;

end;

end;

Stack<T> = class

tp: Node<T>;

public

procedure Push(x: T);

begin

tp := new Node<T>(x,tp);

end;

function Pop: T;

begin

Result := tp.data;

tp := tp.next;

end;

function Top: T;

begin

Result := tp.data;

end;

function IsEmpty: boolean;

begin

Result := tp = nil;

end;

end;

Использование шаблона класса иллюстрируется ниже:

var

si: Stack<integer>;

sr: Stack<real>;

begin

si := new Stack<integer>;

sr := new Stack<real>;

for var i := 1 to 10 do

si.Push(Random(100));

while not si.IsEmpty do

sr.Push(si.Pop);

while not sr.IsEmpty do

write(sr.Pop,' ');

end.

Подстановка конкретного типа-параметра в обобщенный тип называется инстанцированием.

Обобщенные подпрограммы: обзор

Обобщенной подпрограммой (generic) называется подпрограмма, параметризованная одним или несколькими типами. Подпрограмма образуется из обобщенной подпрограммы подстановкой конкретных типов в качестве параметров. Параметры указываются после имени подпрограммы в угловых скобках.

Например, следующая обобщённая функция параметризована одним параметром:

function FindFirstInArray<T>(a: array of T; vaclass="underline" T): integer;

begin

Result := -1;

for var i:=0 to a.Length-1 do

if a[i]=val then

begin

Result := i;

exit;

end;

end;

var x: array of string;

begin

SetLength(x,4);

x[0] := 'Ваня';

x[1] := 'Коля';

x[2] := 'Сережа';

x[3] := 'Саша';

writeln(FindFirstInArray(x,'Сережа'));

end.

При вызове обобщенной подпрограммы тип-параметр обобщения можно не указывать, поскольку компилятор выводит типы параметров шаблона по типам фактических параметров. В данном случае после выведения получено: T=string.

При выведении требуется точное соответствие типов, приведение типов не допускается. Например, при компиляции следующего кода

...

var x: array of real;

begin

SetLength(x,3);

x[0] := 1;

x[1] := 2.71;

x[2] := 3.14;

writeln(FindFirstInArray(x,1));

end.

произойдет ошибка. Причина состоит в том, что первый параметр имеет тип array of real, а второй - тип integer, что не соответствует ни одному типу T в заголовке обобщенной функции. Для решения проблемы следует либо изменить тип второго параметра на reaclass="underline"

FindFirstInArray(x,1.0)

либо явно после имени функции в угловых скобках указать имя типа, которым параметризован данный вызов:

FindFirstInArray&<real>(x,1)

Использование знака & здесь обязательно, поскольку в противном случае компилятор трактует знак < как <меньше<.

Обобщёнными могут быть не только обычные подпрограммы, но и методы классов, а также методы другого обобщённого класса. Например:

type

Pair<T,Q> = class

first: T;

second: Q;

function ChangeSecond<S>(newvaclass="underline" S): Pair<T, S>;

end;

function Pair<T,Q>.ChangeSecond<S>(newvaclass="underline" S): Pair<T,S>;

begin

result := new Pair<T,S>;

result.first := first;

result.second := newval;

end;

var

x: Pair<integer,real>;

y: Pair<integer,string>;

begin

x := new Pair<integer,real>;

x.first := 3;

y := x.ChangeSecond('abc');

writeln(y.first, y.second);

end.

По окончании работы данная программа выведет 3abc.

Обобщенные подпрограммы в качестве параметров

Обобщенная подпрограмма может выступать в качестве формального параметра другой обобщенной подпрограммы.

Например, в классе System.Array имеется несколько статических обобщенных методов с обобщенными подпрограммами в качестве параметров. Так, System.Array.Find имеет следующий прототип:

System.Array.FindAll<T>(a: array of T; pred: Predicate<T>): array of T;