Информатика в техническом университете / Информатика в техническом университете. Объектно ориентированное программирование
.pdf5. Объектная модель Delphi Pascal
SomeObject ;= Т2.Create; |
|
SomeObject.Test(5,'Hello!'); |
{параметры целое число и строка - вызвается |
SomeObject. Test(7); |
метод Test класса Т2} |
{параметр целое число - вызывается метод Test |
класса Т2 с параметром по умолчанию} Перегрузить можно любой метод, в том числе и конструктор:
Туре Tl=class |
|
public |
I: integer; |
Constructor Create;overload; |
|
end; |
|
T2=class(Tl) |
|
public |
|
Constructor Create(aI:Integer);overload; end;
Constructor Tl.Create; Begin
inherited Create; I: =10;
End;
Constructor T2.Create(aI:Integer); Begin
inherited Create; I:=al;
End;
Var SomeObject: T2;
SomeObject: =T2.Create; {вызывается конструктор базового класса - в поле I записано 10}
SomeObject:=Т2. Create(5); {вызьюается конструктор производного класса - в поле I записано 5}
5.3. Свойства
Свойство - это средство Pascal Delphi, позволяющее определять интерфейс доступа к полям класса.
В Delphi различают:
простые или скалярные свойства; свойства-массивы;
индексируемые свойства или свойства со спецификацией index; процедурные свойства.
210
5.3. Свойства
Простые свойства. Описание простых свойств вьшолняется следующим образом (квадратные скобки в данном случае указьюают, что соответствующая спещ1фикация может быть опущена):
property <имя свойства>:<тип>
[read <метод чтения или имя поля>] [write <метод записи или имя поля>] [stored <метод или булевское значение>] [default <константа>];
Спецификации, начинающиеся служебными словами read и write, определяют соответственно методы, которые должны быть использованы для чтения и записи свойства. Если метод чтения неопределен, то свойство недоступно для чтения. Если метод записи неопределен, то свойство недоступно для записи.
Вместо метода чтения или записи возможно указание имени поля. Это означает, что данному свойству соответствует поле в описании класса, куда осуществляется непосредственная запись или откуда выполняется непосредственное чтение (без использования методов).
Остальные спецификации, названные спецификациями сохранения, используются только для свойств, определяемых в секции published, т.е. используемых для «опубликованных» компонент. Булевское значение после stored (вместо которого может быть указан метод, возвращающий булевское значение) определяет, должно ли сохраняться данное свойство компонента при сохранении формы (true - должно, false - не должно) в файле с расышрением
.dfm. Последний спецификатор default определяет стандартное значение свойства, при совпадении значения поля с которым свойство не сохраняется.
Например:
private FValue: integer;
procedure SetValue(AValue: integer); function StoreValue:boolean;
published
property Valuennteger read FValue write SetValue stored StoreValue default 10;.. .
Данное описание определяет свойство для внутреннего поля FValue некоторого класса. Чтение свойства вьшолняется напрямую из поля. Для записи в поле используется специальный метод SetValue. Сохранение в форме вьшолняется, если метод StoreValue возвращает true и значение отлично от 10.
Примечание. Принято называть поле класса, для которого определяется свойство, тем же именем, что и свойство, но с префиксом «F», а соответствующие параметры методов ввода и вывода с префиксом «А». Аналогично, имя метода чтения свойства желательно начинать с префикса «Get», метода записи - с «Set».
211
5. Объектная модель Delphi Pascal
При необходимости в производном классе свойство можно переопределить, изменив доступность и/или спецификации. При этом можно указывать только изменяемые спецификации: остальные - наследуются.
В программе свойства используются как обычные поля, например:
А. Value :=п;
или
к: =А. Value;
соответственно при этом будут вьшолняться следующие операции:
A.SetValue(n);
и
k:=^AFValue;
Простые свойства целесообразно использовать:
-для ограничения доступа к полю (например, доступ только для чтения);
-при необходимости обеспечить при записи или чтении вьшолнение некоторых дополнительных действий (например, при записи в поле необходимо еще и фиксировать факт изменения значения).
Пример 5.3. Использование простых свойств (графический редактор «Окружности» - вариант 2). Продемонстрируем особенности программирования с использованием свойств на примере 5.1. В нем мы разрабатывали приложение, позволяющее рисовать на специальном цоле окна приложения окружности.
Определим в классе два свойства Color и Radius. Изменение значений этих свойств свяжем с перерисовкой окружности. На рис. 5.9 представлена диаграмма класса TMyCircle для этого варианта.
Добавим еще одно изменение: поместим вызов процедуры рисования Draw в конструктор, так как конструирование объекта обьршо связано с его рисованием. Текст модуля Circle имеет вид:
TObject
Поля: Image: TImage; х, у, FRadius: Word; FColor: TColor TMyCircle Методы: Create, Draw, Clear, SetSize, SetColor
Свойства: Color: TColor; Radius: Word Рис. 5.9. Диаграмма класса TMyCircle
212
5.3. Свойства
Unit Circle;
Interface
Uses extctrls,Graphics; Type TMyCircle^class
private x,yFRaditis:Word; FColor.TColor; Image:TImage; Procedure Clear;
Procedure Draw;
Procedure SetSize(ARadius: Word);
Procedure SetColor(AColor:TColor);
public
Constructor Create(aImage:TImage;ax,ay,ARadii4s: Word; AColor:TColor);
property Radius:Word write SetSize; property Color: TColor write SetColor;
end; |
|
|
Implementation |
|
|
Constructor TMyCircle.Create; |
|
|
Begin |
inherited Create; |
|
|
Image:=almage; x:=ax; |
y:=ay; |
|
FRadius: =ARadius; FColor: =AColor; |
|
End; |
Draw; |
|
|
|
|
Procedure TMyCircle.Draw; |
|
|
Begin |
Image. Canvas.Pen. Color: =FColor; |
|
|
Image.Canvas.Ellipse(X'FRadius, y-FRadius, |
|
End; |
|
x+FRadius, y+FRadius); |
|
|
|
Procedure TMyCircle.Clear; |
|
|
Var TempColor: TColor; |
|
|
Begin |
TempColor: =FColor; |
|
|
FColor: =Image. Canvas.Brush. Color; |
|
|
Draw; |
|
|
FColor: "^TempColor; |
|
End; |
|
|
|
|
Procedure TMyCircle.SetSize; |
|
|
||
Begin |
Clear; |
FRadius:=ARadius; |
Draw; |
end; |
Procedure TMyCircle.SetColor; |
|
|
||
Begin |
Clear; |
FColor:-AColor; |
Draw; |
end; |
End.
При такой реализации класса вызов процедуры изменения размера и цвета рисунка будут программироваться как переназначение соответствующего свойства:
213
5. Объектная модель Delphi Pascal
C.Radius: =strtoint(rEdit. Text);
или
С. Color: =ColorDialog. Color;
Прим e Ч a H и e. Именно такой способ программирования лежрп в основе всех стандартных компонент Delphi. Так, например, изменение свойства Visible, определенного для всех визуальных компонент, сопровождается в зависимости от ситуации появлением или исчезновением соответствующего компонента.
Анализ приведенного текста программы показывает, что использование простых свойств позволяет сократить количество компонентов класса, описанных в интерфейсной части (секция public), т.е. увеличивает степень инкапсуляции объектов.
Свойства-массивы. Описание свойств-массивов осуществляется следующим образом (квадратные скобки означают, что соответствующая спецификация может быгь не указана):
property <имя> <список индексных параметров>:<тип>
[read <метод чтения>] [write <метод записи>] [default];
Список индексных параметров заключается в квадратные скобки. Это делает свойства-массивы внешне похожими на обычные массивы. Однако индексные параметры не являются индексами в привычном понимании этого термина. Значения индексных параметров, указанные при обращении к свойствам, передаются в методы чтения и записи в качестве обычных параметров. Соответственно тип индексных параметров может быгь не только порядковьв!, но и вещественным или структурным.
Вспецификациях доступа должны указываться методы, количество, тип
ипорядок следования параметров которых должны соответствовать списку индексных параметров. Параметр-значение в методе записи при этом указывается в конце списка.
Спецификация default используется для указания того, что из всех свойств объекта именно данное принимается по умолчанию (при обращении к объекту может быть опущено).
Например:
private function GetValMas(I:word;F:double):word;
procedure SetValMas(I:word;F:double;AElement:word); public prorerty ValMasfLword, F:double]:word
read GetValMas write SetValMas; default;
Приведенное описание означает, что для объекта определено некоторое свойство-массив, чтение и запись элементов которого выполняются
214
5.3. Свойства
специальными методами. Причем при обращении к данному свойству имя свойства можно не указывать, так как оно объявлено используемым по умолчанию, например:
MyObject[k-^2,s] :=/;
эквивалентно
MyObject. ValMas[k+2,s]:=l;
Свойства-массивы можно использовать для работы со сложными структурами, состоящими из однотипных элементов, например, динамическими массивами (так обычно называют массивы, размещенные в динамической памяти).
Пример 5.4. Использование свойств-массивов (класс «Динамический массив» - вариант 1). Пусть требуется разработать класс для реализации динамического массива с произвольным количеством элементов-байт. Максимальный размер массива необходимо определять при его создании. В процессе работы должен отслеживаться реальный размер массива.
Предусмотреть возможность вьшолнения следующих операций:
-ввод массива из элемента TSringGrid и вывод в такой же элемент;
-модификацию указанного элемента;
-вставку элемента на указанное место;
-удаление элемента с заданным индексом.
Кроме того, предусмотреть возможность обращения к любому элементу массива по индексу и обеспечить контроль правильности выполнения указанных операций.
Unit MasByte;
Interface
Uses SysUtils,Dialogs, Grids;
Type
TMas=array[1..255] of byte;
TMasByte = class(TObject) {класс «Динамичесюш массив»}
private |
|
|
ptr_an: ^TMas; |
{указатель на массив} |
|
len.'byte; |
{максимальная длина массива} |
|
Procedure SetEl(Ind:byte;m:byte); |
{процедура записи элемента} |
|
Function GetEl(Ind:byte):byte; |
{функция чтения элемента} |
|
public |
|
|
n.'Byte; |
{реальный размер массива} |
Constructor Create(an:byte);
Destructor Destroy;override;
215
5. Объектная модель Delphi Pascal
Property Masfind: byte]:byte read GetEl write SetEl;default;
ProcedureModijy(Ind:byte;Value.byte); |
{модификацияэлемента} |
||
Procedure Insert(Ind:byte; Value.byte); |
{вставка элемента} |
||
Function Delete(Ind:byte).byte; |
{удаление элемента} |
||
Function InputMas(Grid:TStringGrid;I,J:integer):boolean; |
{ввод} |
||
Procedure OutputMas(Grid: TStringGrid;I,J:integer); |
{вьюод} |
||
end; |
|
|
|
Implementation |
|
|
|
Constructor TMasByte.Create; |
|
|
|
Begin |
|
|
|
inherited Create; |
|
|
|
GetMem(ptr_an,an); |
len: =an; { n:=0; указывать не надо} |
End;
Destructor TMasByte.Destroy; Begin
FreeMem(ptr_an); inherited Destroy;
End;
Procedure TMasByte.SetEl(Ind:byte;m: byte); Begin
iflnd<=len then
iflnd<=n then ptr_an^flndj:=m else
MessageDlgCB массиве нет'+ inttostr(Ind)+
'-го элемента. \mtError,[mbOk],0)
else
MessageDlgCB массиве моэюно разместить только'+ inttostr(Len) +' элементов.', mtError, [mbOk], 0);
End;
Function TMasByte. GetEl(Ind:byte):byte; Begin
If Ind<^n then Result:=ptr_an^[Ind] else
MessageDlgC В массиве нет '-^inttostr(Ind)+
'-го элемента.',mtError, fmbOkJ,0);
End;
Function TMasByte.InputMas(Grid:TStringGrid;I,J:integer):boolean; Var k:byte; x,er_code: integer;
Begin
with Grid do begin
k:=0; Result: =true;
216
5.3. Свойства
while (Cells[k+I,J]<> ")andResult do begin
Val(Cells[k+lJJ,x, er_code); ifer_code-0 then
ifx<-255 then Insert(k+1,x) else
begin
MessageDlgC Значение не моэюет превышать 255.', mtError, [mbOk],0);
Result: =false; Exit;
end else begin
MessageDlgCB строке обнаруэюены недопустимые символы. \ mtError, [mbOk], 0);
Result: =false; Exit;
end;
k:=k+l;
end;
OutputMas(Grid,I,J);
end;
End;
Procedure TMasByte. OutputMas(Grid: TStringGrid;I,J:integer); Var kbyte;
Begin
with Grid do begin
ifn+I>ColCountthen ColCount:=n+I; for k: =0 to ColCount-1 do
ifk<n then Cells[I-^k,J]:=inttostr(mas[k+l]) |
|
elseCells[I+k,J]:="; |
|
end; |
|
End; |
|
Procedure TMasByte.Modify; |
|
Begin |
Mas[Ind]: = Value; End; |
Procedure TMasByte.Insert; |
|
Var i: integer; |
|
Begin |
|
n: =n+l; |
for i: -n-l downto Ind do Mas[i+l]:=Mas[i\, |
Mas[Ind]:=Value;
End;
217
5. Объектная модель Delphi Pascal
Function TMasByte.Delete; Var i: integer;
Begin
Result: =Mas[Ind];
for i: =Ind+l to n do Mas[i'l]: =Mas[i]; n:-n-l; End;
End,
Для работы с динамическим массивом необходимо создать соответствующий объект:
А: =TMasByte. Create(k);
после чего для обращения к элементам достаточно указать имя объекта и рпадекс, начиная с 1:
А[6]-7;
Приведенный пример демонстрирует, что свойства-массивы создают иллюзию работы с массивом, позволяя не вникать в особенности реализащш конкретной структуры.
Индексируемые свойства (свойства со спецификацией index).
Описание индексируемых свойств вьшолняется следующим образом:
property <имя> : <тип> index <константа>
read <метод чтения> write <метод записи>;
где <константа> - целое число типа Shortlnt.
Обычно одновременно описьгоаются несколько свойств с различными значениями индексов, но одними и теми же методами чтения/записи. Методы чтения/записи должны содержать параметр, через который метод получит конкретное значение индекса. Причем в методе чтения данный параметр должен бьпъ последним, а в методе записи - предпоследним, так как последним в нем описывается параметр, определяющий новое значение свойства. Значение параметра-индекса затем используется для определения поля, соответствующего свойству. Таким полем может быгь, например, элемент
массива: |
|
Туре CMasF^class |
|
private |
|
FMasEl:array[l:3] of word; |
{поле-массив} |
function GetElfInd:byte).word; |
{метод чтения} |
procedure SetEl(Ind:byte;AElement); {метод записи} public
218
|
5.4. Метаклассы |
|
property Elementl:word index 1 read GetEl write SetEl; |
|
property Element2:word index 2 read GetEl write SetEl; |
|
property Elements: word index 3 read GetEl write SetEl; |
end; |
|
Function CMas. GetEl; |
|
Begin |
Result: =FMasEl[Ind\; End; |
Procedure CMas. SetEl; |
|
Begin |
FMasEl[Ind]:=AElement; End; |
Свойства в этом случае использованы для обращения к элементам массива.
Процедурные свойства описывают интерфейс к полям, содержащим указатели на методы. Они в основном применяются для подключения методов обработки событий и будут рассмотрены в разделе 5.6.
5.4. Метаклассы
Delphi содержит достаточно богатый арсенал средств создания и обработки полиморфных объектов. Так в дополнение к заложенной еще в Borland Pascal 7.0 совместимости указателей на базовый и производные классы имеется возможность определения спещ1альных переменных (метаклассов), значением которых являются классы. Имеются также спещ1альные операщш проверки принадлежности объекта некоторой иерархии классов (is) и уточнения класса заданного объекта (as).
Ссылка на класс (метакласс). В тех случаях, когда тип создаваемого объекта или требуемого метода класса не известен на этапе компиляции, обращение к соответствующему классу можно организовать с использованием спещ1альной переменной типа ссылка на класс или метакласс. Объявление такой ссылки вьшолняется следующим образом:
ТУре <имя типа ссылки>=с1а88 of <базовый класс ссылки>;
Var <имя переменной>:<имя типа ссылки>;
Значением переменной данного типа может служить имя базового класса ссылки или класса, производного от него.
В Delphi Pascal стандартно определена ссылка типа TClass, базовым классом которой является класс TObject. Переменной типа TClass можно присвоить имя любого класса Delphi, так как все они наследуются от класса
TObject:
Туре TClass=class of TObject;
Var с: TClass; d: TObject;...
c:=TButton;
d:=c.Create(,..)...
219