Листинг 5.17. Использование оператора is
⇐ ПредыдущаяСтр 5 из 5 unit CheckClass; Uses PolymorphObjects; Interface Procedure DrawFigure (Figure: TGeomFigure); {Заголовок процедуры} Implementation Procedure DrawFigure(Figure: TGeomFigure); {Описание процедуры} Begin If Figure is TLine {Проверка соответствия объекта, на который указывает переменная Figure, классу TLine} Then Figure.Draw {Если тип объекта — TLine, то вызывается метод Draw} Else Expend; {В противном случае — выход из процедуры} End. Оператор as В рассмотренном примере (листинг 5.17) допускается вызов метода Draw из объекта, на который указывает параметр Figure, переданный в процедуру, так как заявленный тип параметра позволяет это сделать — в классе TGeomFigure описан метод Draw. Однако иногда требуется вызвать метод, который реализован не в заявленном классе, а в его наследнике, реальный экземпляр которого и передается в качестве параметра. Попытка сделать это вызовет ошибку компиляции. Для указания компилятору о том, что объект следует рассматривать как экземпляр какого-либо конкретного класса, предусмотрен оператор as, используемый следующим образом: <Ссылка на объект> as <Название класса> В результате такого указания Delphi пытается обращаться к объекту, на который указывает ссылка, как к экземпляру заданного класса. Так. если бы в описании класса TGeomFigure не было метода Draw, а описание его располагалось бы в классе TLine, то метод можно было бы вызвать следующим образом: If Figure is TLine {Проверка соответствия объекта, на который указывает переменная Figure, классу TLine} Then (Figure as TLine).Draw {Если тип объекта — TLine, то вызывается метод Draw} Else Exit; {В противном случае — выход из процедуры} Заметим, что приведение типов может использоваться, в основном, при работе с объектами, изменение иерархии которых невозможно. К таким объектам, например, относятся стандартные объекты Delphi. В остальных случаях наличие подобных конструкций в программе, скорее всего, указывает на неправильно спроектированную иерархию классов.
5.4.3. Абстрактные методы Использование наследования и связанного с ним свойства полиморфизма очень удобно при проектировании сложных систем, состоящих из групп классов, имеющих смысловое единство. Такие классы обычно имеют одного родителя, в котором прописываются заголовки методов, необходимых для поддержки функциональности ветви иерархии. В рассматриваемых нами примерах таким классом был TGeomFigure, в котором метод Draw описывался, но не выполнял каких-либо конкретных действий. Для того, чтобы не описывать «пустых» методов, увеличивая бесполезный размер исходного текста программ, в Delphi предусмотрен специальный модификатор методов abstract (англ. Abstract — абстрактный, фиктивный): Procedure <Класс>.<Метод>(<Список параметров>); virtual; abstract; Или для методов-функций: Function <Класс>.<Метод>(<Список параметров>): <Тип значе-ния>; virtual; abstract; Описание метода, помеченного ключевым словом abstract, в классе, где он описан, не требуется, однако и вызвать его из экземпляра данного класса невозможно. При попытке произвести такой вызов возникнет ошибка времени выполнения программы"Project Projectl.exe raised exception class EAbstractError with message 'Abstract Error'."— "Исключительная ситуация EAbstractError в проекте Projectl.exe". Абстрактный метод всегда является виртуальным (помечен ключевым словом virtual) или динамическим (помечен ключевым словом dynamic) и может быть переопределен в одном из классов-потомков. Соответственно, из экземпляров классов, переопределивших абстрактный метод, его вызов возможен. Абстрактные методы называют иногда чисто виртуальными, пример их использования приведен в листинге 5.18. Листинг 5.18. Использование абстрактных методов; unit AbstractMethods;
Interface Type TGeomFigure = class {Описание класса TgeomFigure с виртуальным абстрактным методом Draw} Procedure Draw; virtual; abstract; End; {Заголовок абстрактного метода. Описательная часть класса не содержит реализации данного метода} TLine = class Procedure Draw; override; End; {Описание класса Tline с переопределенным методом Draw} Implementation Procedure TLine.Draw; Begin {Вывод линии} end; {Описание метода Draw класса TLine, -который в классе-родителе описан как абстрактный} Procedure OsingPolymorph; Var GeomFigure: TGeomFigure; {Переменная — ссылка на экземпляр класса TGeomFigure} Begin GeomFigure:= TLine.Create; GeomFigure.Draw; {В момент выполнения такого вызова переменная GeomFigure должна указывать не на экземпляр класса TGeomFigure, а на экземпляр класса-наследника, переопределившего абстрактный метод Draw. В данном случае, это экземпляр класса TLine} GeomFigure.Free; end; End.
5.4.4. Полиморфизм и property-свойства Рассмотрим пример, приведенный в листинге 5.19. Отметим использование свойства полиморфности объектов в рассмотренном примере. При установке значения property-свойству Color автоматически вызывается метод SetColor, которому в качестве параметра передается новое значение цвета. Данное значение заносится в protected-свойство f Color, а затем производится автоматический вызов метода Draw. Метод Draw является виртуальным и может быть переопределен в классах-наследниках. При установке какого-либо значения property-свойству Color класса-наследника будет вызвана та версия метода Draw, которая описана именно в нем, а не в классе TGeomFigure. Таким образом, при отсутствии информации о виде фигур, выводимых классами-наследниками, в классе TGeomFigure полностью реализована логика изменения цвета этой фигуры. Такой подход позволяет локализовать отдельные фрагменты логики сложных классов уже на стадии проектирования вершины иерархии, существенно упрощая тем самым разработку программного продукта в целом. Листинг 5.19. Полиморфизм и property-свойства unit Geom5; Interface Type TGeomFigure = class Protected fColor: Integer; {Описание свойства с областью видимости protected} Procedure Draw; virtual, {Метод прорисовки геометрической фигуры (виртуальный, предназначен для переопределения в классах-наследниках)} Procedure SetColor(aColor: Integer); {Процедура установки protected- -свойства fColor} Public Property Color: Integer read fColor write SetColor;
{Описание property-свойства Color} End; Implementation Procedure TGeomFigure.SetColor(aColor: Integer); Begin fColor:= aColor; Draw; end; {Процедура установки protected-свойства fColor заносит новое значение свойства в protected-свойство fColor и вызывает метод Draw для автоматической перерисовки фигуры при смене ее цвета} Procedure TGeomFigure.Draw; Begin end; Procedure UsingFigure; Var Figure: TGeomFigure; iColor: Integer; Begin Figure:= TGeomFigure.Create(3); Figure.Color:= 13; {Изменение значения property-свойства Color, автоматически вызывается метод SetColor, изменяющий значение свойства fColor, и метод Draw, выводящий изображение фигуры на экран с использованием нового цвета} iColor:= Figure.Color; {Обращение к property-свойству Color. В качестве значения, В соответствии с описанием данного property-свойства, возвращается значение свойства fColor} Figure.Free, end; End. 5.5. Ключевое слово Self Для выполнения некоторых задач, методам, реализованным в классе, иногда требуется сослаться на объект (экземпляр класса), из которого вызван метод во время выполнения программы. Поскольку такая ссылка на экземпляр не всегда известна в процессе разработки программы, в Delphi введено ключевое слово Self, вместо которого на этапе выполнения будет подставлен конкретный адрес объекта. Ссылка Self может использоваться как обычная переменная, ссылающаяся на класс. В качестве примера можно привести метод некоторого класса, который выдает ссылку на экземпляр, из которого вызван данный метод во время выполнения программы: Туре AnyClass = class Function GetSelf:TObject; end; Function AnyClass.GetSelf: TObject; Begin Result:= Self; {Возвращаем ссылку на экземпляр, из которого вызван метод} end; End. Использование ссылки Self может быть необходимо при создании компонентов, в конструкторе которых следует передать ссылку на компонент-владелец, не известную на этапе разработки программы.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|