
- •Основные механизмы и положения объектно-ориентированного программирования
- •5.1. Инкапсуляция
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •5.2. Наследование
- •Interface
- •Implementation
- •Interface
- •Implementation
- •5.3. Жизненный цикл экземпляра класса
- •Interface
- •Implementation
- •Inherited;
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •5.4. Полиморфизм
- •5.4.1. Совместимость объектов
- •Класс в Экземпляр
- •Interface Type
- •Implementation
- •Interface
- •Implementation
- •If Figure is tLine
- •Interface
- •Implementation
- •Interface
- •Implementation
- •IColor: Integer;
5.4. Полиморфизм
5.4.1. Совместимость объектов
Очевидно, что при наследовании классов друг от друга количество свойств и методов увеличивается от класса к классу (или, как минимум, не уменьшается). Все объекты некоторого класса могут иметь доступ к методам и свойствам, реализованных в тех классах, от которых он унаследован. В результате такого свойства объектов появляется теоретическая возможность присвоить переменной-ссылке на экземпляр класса реальную ссылку на экземпляр другого класса. Причем присваиваемый объект должен быть экземпляром класса, находящимся ниже по иерархии, чем тот, который был указан при описании переменной.
Н
Класс А
Экземпляр
а
рис. 5.1 представлены классы, образующие
иерархию. Один из классов -Класс А —
является родительским для всех остальных.
Соответственно, если некоторая переменная
описана как ссылка на экземпляр Класс
А, то на самом деле она может указывать
еще и на Класс Б, и на Класс В.
Класс Б
Экземпляр
Класс в Экземпляр
Рис. 5.1. Совместимость объектов
Как и все объектно-ориентированные языки программирования, Delphi поддерживает свойство полиморфизма объектов при наследовании, которое состоит в правильном выборе виртуального метода, вызываемого из переменной-ссылки на объект. Вне зависимости от того, на экземпляр какого класса указывает переменная-ссылка в соответствии со своим описанием, будет вызван виртуальный метод, описанный в классе, на который реально указывает ссылка, а не его версия, описанная в классе, сопоставленном типу ссылочной переменной.
Рассмотрим (листинг 5.16), например, классы Tline HTCircle, являющиеся наследниками класса TGeomFugure и переопределяющие виртуальный метод Draw, чтобы придать ему функциональность, необходимую для вывода каждой конкретной геометрической фигуры. Опишем переменную, которая является ссылкой на экземпляр класса TGeomFigure и присвоим ей ссылку на экземпляр класса TLine.
Такая операция возможна, так как класс TLine является наследником класса TGeomFigure. При вызове метода Draw данной переменной этот метод будет вызван в том виде, как он описан в классе TLine, а не в классе TGeomFigure. В этом и выражается полиморфизм (многоформенность) объектов, находящихся в одной иерархии.
Свойство полиморфизма поддерживается с помощью так называемого позднего связывания (происходящего во время выполнения программы) переменных-экземпляров с методами, в отличие от раннего связывания (на этапе компиляции).
Листинг 5.16. Иллюстрация полиморфизма
unit PolymorphObjects;
Interface Type
TGeomFigure = class {Описание класса TgeomFigure с виртуальным методом Draw}
Procedure Draw; virtual;
End;
TLine = class
Procedure Draw; override; {Описание класса TLine с переопределенным
методом Draw}
End;
Implementation
procedure TGeomFigure .Draw;
Begin {Описание метода Draw класса TGeomFigure, метод ничего не делает}
End;
Procedure TLine.Draw;
begin
{Вывод линии}
end; {Описание метода Draw класса TLine,
метод выводит линию}
Procedure UsingPolymorph;
{Описание процедуры, использующей полиморфизм объектов}
Var
GeomFigure: TGeomFigure; {Описание переменной-ссылки на экземпляр класса TGeomFigure}
begin
GeomFigure := TLine.Create; {Создание экземпляра класса TLine и занесение ссылки на него в переменную-ссылку на экземпляр класса TGeomFigure}
GeomFigure.Draw; {Вызов метода Draw из переменной GeomFigure, реально вызываемый метод описан в классе TLine (рисование линии) }
GeomFigure.Free; {Разрушение объекта, на который указывает переменная GeomFigure, если бы класс TLine переопределял деструктор, то был бы вызван деструктор, описанный в классе Tline}
end;
End.
5.4.2. Определение принадлежности к классу и приведение типов объектов
Оператор is
При использовании полиморфизма нередко требуется определить, ссылка на объект какого именно типа находится в той или иной переменной. Для решения задач такого рода все объекты содержат информацию о классе — так "называемую RTTI-информацию (от англ. Run Time Type Information — информация времени выполнения о типе), для доступа к которой во всех классах имеются методы, унаследованные ими от класса тobject. Однако использование этих методов не рекомендуется разработчиками, а вместо них предусмотрен оператор is, проверяющий принадлежность объекта к заданному классу.
Оператор is возвращает логическое значение (True или False) и используется в следующем виде:
<Ссылка на объект> is <Название класса>
Проиллюстрируем использование оператора is на примере модуля (листинг 5.17), подключающего к себе модуль PolymorphObjects, разработанный в предыдущем примере. Реализуем процедуру, которая получает в качестве параметра ссылку на экземпляр класса TGeomFigure, и определяет, не принадлежит ли объект, на который реально указывает ссылка, к классу TLine. Если объект является экземпляром класса TLine, то вызовем его метод Draw, в противном случае процедура должна завершиться.
Листинг 5.17. Использование оператора is
unit CheckClass;
Uses PolymorphObjects;