1. Доступ к О-полям и О-методам родительских типов точно такой же, как если бы они были описаны в самом потомке.
2. Идентификаторы О-полей потомка не должны совпадать с идентификаторами О-полей родительских типов. Если в потомке описывается О-метод с тем же именем, что и у родителя, то он перекрывает (подавляет) его.
3. Любое изменение текста в родительском О-методе автоматически оказывает влияние на все О-методы порожденных типов, которые его вызывают.
Полиморфизм – свойство родственных объектов решать схожие по смыслу проблемы разными способами. Например, если абстрактный объект Фигура (рис. 5) обладает методом Draw прорисовки её на экране монитора, то все потомки типа Фигура могут иметь собственные методы Draw, перекрывающие аналогичный метод родителя.
Рис. 5. Пример иерархии объектов.
Таким образом, изменяя алгоритм О-метода в потомках можно придавать этим потомкам специфические свойства, отсутствующие у родителя. В результате в О-родителе и О-потомке будут действовать два одноименных О-метода, имеющие разную алгоритмическую основу – следовательно придающие объектам разные свойства – это и есть полиморфизм.
Переопределение методов родителя может осуществляться с помощью статических методов и динамических методов. Рассмотрим их отличие на примере простой ООП-программы.
Program OOP_Primer;
Uses CRT, Graph;
Type TFigure = Object
x, y :Integer; { координаты фигуры}
color :Word; { и её цвет}
Procedure Init ( ax, ay :Integer; col :Word );
Procedure Draw ( col :Word );
Procedure Show; Procedure Hide;
Procedure MoveTo ( dx, dy :Integer );
End;
TPoint = Object ( TFigure ) { TFigure – имя родительского типа }
Procedure Draw ( col :Word );
End;
TCircle = Object ( TPoint )
R :Integer; { радиус окружности }
Procedure Init (ax,ay,aR :Integer; col :Word );
Procedure Draw ( col :Word );
End;
{ реализация методов TFigure }
Procedure TFigure. Init ( ax, ay :Integer; col :Word ); { инициализация фигуры }
Begin x := ax; y := ay; color := col; End;
Procedure TFigure. Draw ( col :Word ); { рисование фигуры }
Begin {ничего не делает, потомки должны перекрывать этот метод} End;
Procedure TFigure. Show; { рисование фигуры цветом color}
Begin Draw ( Color ); End;
Procedure TFigure. Hide; {стирание фигуры } Begin Draw ( GetBkColor ); End;
Procedure TFigure. MoveTo ( dx, dy :Integer ); { перемещение фигуры }
Begin Hide; x := x+dx; y := y+dy; Show; End;
{ реализация методов TPoint }
Procedure TPoint. Draw ( col :Word ); { рисование точки }
Begin PutPixel ( x, y, col ); End;
{ реализация методов TCircle }
Procedure TCircle. Init (ax,ay,aR :Integer; col :Word ); { инициализация окружности } Begin Inherited Init ( ax, ay, col ); R := aR; End;
procedure TCircle. Draw ( col :Word ); { рисование окружности }
Begin SetColor ( col ); Circle ( x, y, R ); End;
{ $I GrInit } Var VCircle : TCircle;
Begin
GrInit;
VCircle. Init ( 320, 240, 100, 12 );
VCircle. Show;
ReadKey;
CloseGraph;
End.
Хотя эта программа составлена синтаксически правильно и должна нарисовать окружность на экране, в действительности этого не будет. Дело в том, что вызовы методов и их связи установлены статически на этапе трансляции и в дальнейшем не изменяются. Поэтому, при выполнении метода VCircle. Show будет вызываться метод TFigure. Draw, а не метод TCircle. Draw. Связи между методами в этой программе показаны на рис. 6.
Рис. 6. Пример раннего ( во время трансляции ) связывания.
При использовании статических методов транслятор выполняет следующие действия по связыванию О-методов:
1. Устанавливает тип объекта, вызывающий данный О-метод.
2. Производит поиск О-метода в рамках данного типа. Если О-метод найден, то назначается вызов этого О-метода, иначе выполняется п.3.
3. Продолжает поиск О-метода в прародительских типах вверх по иерархии. Если поиск успешен, то назначается вызов, иначе – ошибка.
Из этого следует вывод: если О-метод прародителя вызывает другие методы, то они будут методами прародителя, даже если потомки имеют собственные подобные методы.
Объект VСircle имеет собственный метод Draw, однако его унаследованный метод Show жестко (статически) связан с методом Draw объектного типа TFigure, который ничего не рисует. Конечно, можно снабдить всех потомков собственными статическими методами Show и Hide, однако в объектно-ориентированном программировании реализуется более эффективный подход – механизм позднего связывания и виртуальные методы.
Таким образом, для реализации полиморфизма в языке программирования требуются не статическое, а динамическое (во время выполнения программы) связывание экземпляров объектов с методами, которые поддерживают полиморфические действия. |