Листинг 5.8. Пример описания и использования property-свойства



Unit Properties;                             {Заголовок модуля}

Interface

Type

ABC4 = class

Private

 fa, fb, fc: Double; {Все свойства имеют узкую область видимости}

protected                      {Все методы имеют область видимости protected}

Procedure SetA(NewA: Double); {Процедура установки значения свойства fa}

Procedure SetB(NewB: Double); {Процедура установки значения свойства fb}

 

Function GetA: Double; {Функция получения значения свойства fa}

Function GetB: Double; {Функция получения значения свойства fb}

Function GetC: Double; {Функция получения значения свойства fc}

Published                       {Раздел описания property-свойств, доступных вызывающему фрагменту программы}

property A:Double read GetA write SetA;

{Описание property-свойства А, для которого задана функция чтения GetA и процедура установки SetA. Свойство будет доступно вызывающему фрагменту программы для чтения и записи}

  property B:Double read GetB write SetB;

{Описание property-свойства В, для которого задана функция чтения GetB и процедура установки SetB. Свойство будет доступно вызывающему фрагменту программы для чтения и записи}

property C:Double read GetC;

{Описание property-свойства В, для которого задана функция чтения GetC, но не задана процедура установки. Свойство будет доступно вызывающему фрагменту программы только для чтения}

end;

 

Implementation

 Procedure ABC4.SetA(NewA: Double); {Описание метода SetA}

Begin

fa := NewA;      {Занесение нового значения в private-свойство fa}

 fc := fa * fb;   {Пересчет произведения и занесение результата в свойство fc} .

end;

Procedure ABC4.SetB(NewB: Double);      {Описание метода SetB}

Begin

fb := NewB;       {Занесение нового значения в private-свойство fb}

fc := fa * fb;    {Пересчет произведения и занесение результата в свойство fc}

end;

Function ABC4.GetA: Double;             {Описание метода GetA}

Begin

Result   := fa;              {Результат функции — значение private-свойства fa}

end;

Function ABC4.GetB: Double;             {Описание метода GetB}

Begin

Result   := fb;            {Результат функции — значение private-свойства fb}

end;

Function ABC4.GetC: Double;             {Описание метода GetC}

Begin

Result   := fc;  {Результат функции — значение private-свойства fc}

end;

end.                    {Окончание модуля}

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

Заметим, что вместо функции чтения и процедуры установки может, быть указано одно из обычных свойств, вне зависимости от его области видимости. В рассмотренном примере такую возможность следует применить при описании property-свойств а, b и с, указав вместо функций чтения свойства fa, fb и fc, соответственно. Модифицированный текст модуля приведен в листинге 5.9.

Листинг 5.9. Пример описания и использованияproperty-свойства (модифицированный)

Unit Properties; {Заголовок модуля}

Interface

Type

ABC4 = class

Private

 fa, fb, fc: Double; {Все свойства имеют узкую область видимости}

protected       {Все методы имеют область видимости protected}

Procedure SetA(NewA: Double); {Процедура установки значения свойства fa}

 Procedure SetB(NewB: Double);   {Процедура установки значения свойства fb}

 Published                {Раздел описания property-свойств, доступных вызывающему фрагменту программы}

property A:Double read fa write SetA;  {Для установки значения property-свойства используется метод SetA, а для чтения private-свойство fa}

Property B:Double read fb write SetB; 

{Для установки значения property-свойства используется метод SetB, а для чтения private-свойство fb}

Property С:Double read fc;     

{Для чтения property-свойства используется значение private-свойства fc}

end;

Implementation

Procedure ABC4.SetA(NewA: Double); {Описание метода SetA}

Begin

fa := NewA;

fc := fa * fb;

end;

Procedure ABC4.SetB(NewB: Double); {Описание метода SetB}

Begin

fb:= NewB;

fc:= fa * fb;

end;

end.  {Окончание модуля}

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

Наследование

 

5.2.1. Основы наследования

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

При описании дочернего класса с использованием наследования имя родительского класса указывается в скобках после ключевого слова с1ass| в заголовке интерфейсной части описываемого класса:

Туре

<Имя класса> = class(<Имя родительского класса>) {Заголовок описания}

......... {Описание собственных свойстви методов}

End;

Класс-наследник может быть описан на основе любого другого класса, вне зависимости от того, является ли родительский класс в свою очередь дочерним. Более того, все классы в Delphi являются наследниками от класса TObject, даже если это явно не указывается.

Класс TObject инкапсулирует основные методы и свойства, связанные с общим поведением объектов. К ним относятся такие как создание, инициализация и разрушение объектов; поддержка идентификации их принадлежности к классу во время выполнения программы и многие другие, связанные с интеграцией объектов, созданных в Delphi, в среду выполнения программы, то есть операционную систему. Таким образом, экземпляры любого класса в Delphi автоматически приобретают все эти возможности.

 

5.2.2. Переопределение методов

Часто встречается ситуация, когда один или несколько методов дочернего класса должны работать не так, как в родительском классе. В качестве примера можно привести класс TGeomFigure, представляющий собой абстрактную геометрическую фигуру, и имеющий метод Draw для ее рисования. Наследниками этого класса могли бы быть классы TCircle для работы с окружностями, TLine для работы с линиями, и так далее.

Очевидно, что все дочерние классы в такой ситуации должны изменить метод Draw, чтобы корректно отображать фигуры, которым они соответствуют. Изменение функциональности унаследованных методов в дочерних классах называется переопределением методов.

Механизм переопределения

 

Для переопределения метода, реализованного в объекте-родителе, следует:

 

♦ указать его заголовок в интерфейсной части описания дочернего класса без изменения имени, списка параметров и возвращаемого значения (если метод является функцией);

♦ указать после заголовка метода ключевое слово override.Если ключевое слово override не указано, то метод не переопределяется.

♦ реализовать метод (создать программный код) в описательной части объекта по обычным правилам. При этом в заголовке метода ключевое слово override не указывается.

 

Чтобы метод мог быть переопределен в дочерних классах, он должен быть помечен ключевыми словами virtualили dynamicв интерфейсной части класса-родителя. Ключевое слово virtual указывает на то, что метод должен быть занесен в так называемую таблицу виртуальных методовТВМ), а ключевое слово dynamic на то, что метод должен быть найден ло имени в дереве родительских объектов.

Разница между использованием virtual и dynamic заключается в направлении оптимизации компилятором вызовов переопределяемых методов. Методы, помеченные virtual, оптимизируются по скорости, а zynamic-методы по размеру программного кода. В большинстве случаев рекомендуется использование виртуальных методов, а использование динамических методов целесообразно при высоких степенях вложенности cвязей родитель-наследник.

Приведем описание класса TwoNums с двумя свойствами а и Ь, и методом GetResult, возвращающим сумму свойств. Далее, от этого класса эпишем наследника ThreeNums, имеющего уже три свойства — а, b и с, и переопределяющего метод GetResult таким образом, чтобы возвра­щать сумму не двух, а трех чисел (листинг 5.10).


Дата добавления: 2018-04-04; просмотров: 179;