Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Свойства






В предыдущем параграфе обсуждались преимущества, которые дают интерфейсные методы класса. Однако с точки зрения пользователя класса применение методов для доступа к полям имеет небольшой недостаток – громоздкость вызова. Развитие концепций ООП привело к появлению понятия свойства (property). Свойство – это элемент класса, работа с которым происходит так же, как с полем объекта. Разница между полем и свойством заключается в следующем: обращение к свойству компилятор транслирует в вызов метода или обращение к полю, следовательно, при работе со свойствами могут выполняться некоторые действия.

В Object Pascal для объявления свойства используется ключевое слово property. Далее следует имя свойства и указывается его тип. После директивы read указывается имя поля или метода для чтения свойства. Аналогично, после директивы write указывается имя поля или метода для записи свойства. Считается, что свойство записывается, когда ему присваивается некое значение, иначе свойство читается. Тип полей, употребляемых после read и write, должен совпадать с типом свойства. Метод, используемый для чтения простого свойства, должен быть функцией без параметров, тип возвращаемого значения которой совпадает с типом свойства. Метод для записи – процедура с одним параметром, имеющим тип свойства. Принято соглашение, согласно которому имена методов чтения свойств начинаются с префикса Get, а имена методов записи – с префикса Set. Объявление свойства может следовать только после объявления полей и методов, которые используются свойством.

Добавим свойства в класс TPerson:

type TPerson = class

private

fName: string;

fAge: Integer;

public

procedure SetAge(Age: Integer);

function GetAge: Integer;

procedure SetName(Name: string);

function SayName: string;

property Age: Integer read GetAge write SetAge;

property Name: string read SayName write SetName;

end;

Работу со свойствами демонстрирует следующий фрагмент кода:

var Man: TPerson;

...

Man.Name: = 'Alex'; // транслируется в Man.SetName('Alex')

Man.Age: = 101; // транслируется в Man.SetAge(101)

Подчеркнём, что свойства класса призваны облегчить работу с объектом для пользователя. Фактически, свойства «живут» только до компиляции программы, во время которой заменяются методами или полями. В отличие от полей свойства не занимают места в памяти. Это накладывает определённые ограничения на их использование. Свойства нельзя передавать в качестве var-параметров в подпрограммы, к ним нельзя применять операцию взятия адреса.

Употребление свойств позволяет «сэкономить» на методах класса. Например, в классе TPerson методы GetAge и SetName введены только для того, чтобы обеспечить полный доступ к полям, никаких особых действий они не выполняют. Заменим в определении свойств эти методы полями fAge и fName. В свою очередь, методы, обслуживающие свойства, поместим в секцию private, так как именно свойства теперь будут составлять интерфейс класса:

type TPerson = class

private

fName: string;

fAge: Integer;

procedure SetAge(Age: Integer);

function SayName: string;

public

property Age: Integer read fAge write SetAge;

property Name: string read SayName write fName;

end;

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

Одна пара методов может использоваться для обслуживания нескольких свойств. Чтобы различить в теле метода, к какому свойству относится его вызов, свойству присваивается индекс, само свойство в этом случае называется индексированным:

type TExample = class

...

function Get(A: Integer): byte;

procedure Set(B: Integer; C: byte);

...

property Prop1: byte index 0 read Get write Set;

property Prop2: byte index 1 read Get write Set;

property Prop3: byte index 2 read Get write Set;

end;

Здесь Prop1, Prop2, Prop3 – индексированные свойства. Для создания таких свойств используется директива index с целой уникальной константой. Для чтения всех индексированных свойств применяется метод-функция с одним целым параметром. Запись индексированных свойств осуществляется методом-процедурой, первый параметр которой – целое число. Применение полей для чтения и записи индексированных свойств невозможно.

var Ex: TExample;

...

Ex.Prop1: = 100; // Ex.Set(0, 100)

k: = Ex.Prop3; // k: = Ex.Get(2)

Рассмотрим пример класса TArray. Он будет представлять массив вещественных чисел, в котором кроме самих чисел хранится количество элементов, а также имеется свойство для получения максимального элемента. Начальный вариант такого класса может выглядеть так:

type TArray = class

private

fData: array[1..1000] of double; // массив «с запасом»

fLength: Integer; // реальная длина массива

public

procedure WriteElement(Ind: Integer; Value: double);

function ReadElement(Ind: Integer): double;

function FindMax: double;

property Length: Integer read fLength;

property Max: double read FindMax;

end;

 

procedure TArray.WriteElement(Ind: Integer; Value: double);

begin

if (Ind > 0) and (Ind < = 1000) then

begin

fData[Ind]: = Value;

if Ind > fLength then fLength: = Ind;

end;

end;

 

function TArray.ReadElement(Ind: Integer): double;

begin

if (Ind > 0) and (Ind < = fLength) then Result: = fData[Ind]

else Result: = 0

end;

 

function TArray.FindMax: double;

var i: Integer;

begin

Result: = fData[1];

for i: = 2 to fLength do

if fData[i] > Result then Result: = fData[i]

end;

...

var Mas: TArray;

...

Mas.WriteElement(1, 10);

Mas.WriteElement(2, 100);

Mas.WriteElement(10, 1);

k: = Mas.Max; // k = 100

l: = Mas.Length; // l = 10

Обратите внимание: свойства Length и Max являются свойствами только для чтения. Более того, свойство Max вообще можно считать «виртуальным», так как оно не связано ни с одним полем класса (но пользователь класса этого не заметит).

Для пользователя класса TArray естественным желанием является получить более удобный способ доступа к данным в fData. Object Pascal разрешает объявлять свойства-массивы. Подобные свойства используются в основном в классах, данные которых подразумевают доступ с использованием различных индексаторов. Добавим свойство-массив в класс TArray (и перенесём методы WriteElement и ReadElement в секцию private):

type TArray = class

private

...

procedure WriteElement(Ind: Integer; Value: double);

function ReadElement(Ind: Integer): double;

public

...

property Data[I: Integer]: double read ReadElement

write WriteElement;

end;

Для объявления свойства-массива после имени свойства в квадратных скобках указывается имя и тип индекса. Как и для индексированных свойств, для доступа к свойствам-массивам возможно только использование методов. Первый параметр этих методов должен совпадать по типу с индексом свойства. Ниже приведён пример работы со свойством Data, и указано, во что транслируются обращения к нему:

for i: = 1 to 5 do

Mas.Data[i]: = 1000; // транслируется в Mas.WriteElement(i, 1000)

Тип индекса свойства-массива не ограничен диапазоном (индекс может быть любого типа – строка, вещественное число, класс). Допускается работа только с элементами свойства-массива, а не со всем свойством целиком.

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

Если при описании свойства-массива добавить в конце директиву default, то такое свойство становится основным свойством класса. Для основного свойства можно указывать индекс непосредственно после имени объекта, не используя идентификатор свойства. Сделаем свойство Data основным:

type TArray = class

...

property Data[I: Integer]: double read ReadElement

write WriteElement; default;

end;

Теперь с ним можно работать так:

for i: = 1 to 5 do

Mas[i]: = 1000; // вместо Mas.Data[i]: = 1000

Только свойство-массив может быть основным свойствам класса. У класса может быть только одно основное свойство.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.