Шаг 136.
Свойства-массивы

    На этом шаге мы рассмотрим использование свойств-массивов.

    На первый взгляд свойства-массивы отличаются от простых свойств приблизительно также, как переменные типа "массив" от переменных простых типов, то есть наличием индекса. Однако, способ описания и использования индексов в свойствах-массивах имеет достаточно большие различия по сравнению с индексацией обычных массивов. Остановимся отдельно на отличиях свойств-массивов как от простых свойств, так и от простых массивов.

    Отличия свойств-массивов от простых свойств:

  1. Главной особенностью объявления является наличие списка индексных параметров. Обратим внимание, не индексов, а именно параметров, определяющих индексы, которые записываются подобно формальным параметрам процедур с указанием типа. При описании списка индексных параметров используются не круглые, квадратные скобки. В этом проявляется отличие свойств-массивов как от простых свойств, так и от простых массивов.
  2. В описании спецификаторов доступа read и write могут быть указаны только идентификаторы методов. Прямое использование идентификатора поля запрещено.
  3. Метод, указанный в спецификаторе чтения, должен быть функцией, у которой количество, типы и порядок расположения параметров соответствуют описанию индексных параметров свойства. Тип результата, возвращаемого этой функцией должен совпадать с типом свойства.
  4. Метод, указанный в спецификаторе записи, должен быть процедурой, у которой количество, типы и порядок расположения начальных параметров соответствуют описанию индексных параметров свойства. Кроме того, список параметров процедуры должен иметь один дополнительный параметр такого же типа, как у свойства, для передачи нового значения. Этот параметр может быть или параметром-значением, или параметром-константой.
  5. Свойства-массивы не могут быть опубликованными (published).

    Отличия свойств-массивов от переменных типа "массив":

  1. Обращение к свойству-массиву как к единому целому не допускается. Разрешены действия только с его отдельными элементами.
  2. Тип индексов у свойств-массивов может быть любым, а не только порядковым.

    Покажем использование свойств-массивов на следующем примере.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TVectorClass = class
  private
    FVector : array [1..10] of Word;
  protected
    function GetVector (Index : Integer) : Word;
    procedure SetVector (Index : Integer; Value : Word);
    procedure AddToVectorElem (Index : Integer; Value : Word);
  public
    property Elements [Index : Integer] : Word
        read GetVector
        write SetVector;    default; { свойство по умолчанию }
    property AddToElement [Index : Integer] : Word
        write AddToVectorElem;
  end;


var
  Form1: TForm1;
  MyVector : TVectorClass;

implementation

{$R *.dfm}

function TVectorClass.GetVector(Index : Integer) : Word;
begin
  Result := FVector [Index];
end;

procedure TVectorClass.SetVector (Index : Integer; Value : Word);
begin
  FVector [Index] := Value;
end;

procedure TVectorClass.AddToVectorElem(Index : Integer; Value : Word);
begin
  FVector [Index] := FVector [Index] + Value;
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  i : Integer;
  S : String;
begin
  MyVector := TVectorClass.Create;
  for i := 1 to 10 do
    MyVector[i] := i; { Имя свойства Elements может быть }
    {опущено, поскольку это свойство будет принято по умолчанию}
  for i := 1 to 10 do
  begin
    Str(MyVector.Elements[i], S);
    Form1.Memo1.Lines.Add(S);
  end;
  for i := 1 to 10 do
    MyVector.AddToElement[i] := 5;  { Имя свойства }
    { AddToElement всегда должно быть указано полностью }
  for i := 1 to 10 do
  begin
    Str (MyVector[i], S);
    Form1.Memo2.Lines.Add(S);
  end;
  MyVector.Free;
end;

end.
Текст этого примера можно взять здесь.

    Результат:


Рис.1. Результат работы приложения

    Обратите внимание, что, несмотря на все перечисленные отличия, обращение к элементам свойства-массива выполняется так же, как и к элементам обычного массива.

    Кроме того, как отмечалось выше, директива default в свойствах-массивах является не спецификатором сохранения, а указателем того, какое из свойств-массивов данного класса будет приниматься по умолчанию. В рассмотренном примере - это свойство Elements. Как видно из кода примера, к свойству Elements возможны два способа обращения:

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

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TRow  ='a'..'h' ;
  TColumn  = 1..8;
  TCheckersBoard =   class
  private
    FBoard : array [TRow,TColumn] of  Char;
  protected
    function GetChecker (Row: TRow; Col: TColumn):Char;
    procedure  SetChecker (Row: TRow; Col: TColumn; const Value: Char);
  public
    property Board [Row: TRow; Col: TColumn]: Char
      read GetChecker write SetChecker; default;
  end;

var
  Form1: TForm1;
  MyBoard : TCheckersBoard;


implementation

{$R *.dfm}

function TCheckersBoard.GetChecker (Row : TRow; Col :TColumn) : Char;
begin
  Result := FBoard [Row,Col];
end;

procedure TCheckersBoard.SetChecker (Row : TRow; Col : TColumn; 
           const Value : Char) ;
begin
  FBoard [Row, Col] :=Value;
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  i : TRow;
  j : TColumn;
  s : String;
  k,l : Integer;
begin
  MyBoard := TCheckersBoard.Create;
  for i := 'a' to 'h' do
    for j :=1 to 8 do
       MyBoard [i,j]:=' ';
  Memo1.Lines.Clear;
  k:=0;
  for i := 'a' to 'h' do
  begin
    if Ord(i) mod 2 = 1 then
    begin
      MyBoard [i,1]:='Б';
      MyBoard [i,3]:='Б';
      MyBoard [i,7]:='Ч';
    end
    else
    begin
      MyBoard [i,2]:='Б';
      MyBoard [i,6]:='Ч';
      MyBoard [i,8]:='Ч';
    end;
  end;
  for j :=1 to 8 do
  begin
    S:='';
    for i := 'a' to 'h' do
         S:=S+MyBoard [i,j];
    Memo1.Lines.Add(S);
  end;
end;

end.
Текст этого примера можно взять здесь.

    Результат:


Рис.2. Результат работы приложения

    На следующем шаге мы рассмотрим свойства со спецификатором index.




Предыдущий шаг Содержание Следующий шаг