Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
8.DOC
Скачиваний:
0
Добавлен:
21.12.2018
Размер:
318.98 Кб
Скачать
  1. Наследование правил и полиморфизм

Наследование полей данных представляет собой достаточно узкую область всего механизма наследования в ООП. Поля данных наследуются всегда. В порожденном объекте эти поля переопределять нельзя. Иначе говоря, если поле данных уже определено в иерархии объектов, никакой производный тип не может иметь поле данных с точно таким же именем.

Более сложным и разнообразным является механизм наследо­вания методов. В одном из вариантов предполагается, что методы предка наследуются так же само, как и поля данных, но, при желании, они могут быть переопределены с сохранением прежних имен. Для замены унаследованного метода определяется новый метод с тем же именем, но с другим телом и (при необходимости) с другим набором параметров. В этом случае возникает очевидная неоднозначность в выборе варианта метода при его вызове. Для статических объектов (см. ниже) неоднозначность устраняется с помощью явного указания имени объекта, в котором инкапсулирован этот метод, т. е. для вызова метода используется спецификация Ancestor.Method, где Ancestor является именем прародительского типа объекта, а Method – имя наследуемого метода.

Пояснить это можно на примере объекта Circle:

Circle = object(Point)

Radius : Integer;

procedure Init(InitX, InitY : Integer; InitRadius : Integer);

procedure Show;

procedure Hide;

procedure Expand(ExpandBy : Integer);

procedure MoveTo(NewX, NewY : Integer);

procedure Contract(ContractBy : Integer);

end;

procedure Circle.Init(InitX, InitY : Integer; InitRadius : Integer);

begin

Point.Init(InitX, InitY);

Radius := InitRadius;

end;

procedure Circle.Show;

begin

Visible := True;

Graph.Circle(X, Y, Radius);

end;

procedure Circle.Hide;

var

TempColor : Word;

begin

TempColor := Graph.GetColor;

Graph.SetColor(GetBkColor);

Visible := False; Graph.Circle(X, Y, Radius);

Graph.SetColor(TempColor)

end;

procedure Circle.Expand(ExpandBy : Integer);

begin

Hide;

Radius := Radius + ExpandBy;

if Radius < 0 then Radius := 0;

Show

end;

procedure Circle.Contract(ContractBy : Integer);

begin

Expand(-ContractBy)

end;

procedure Circle.MoveTo(NewX, NewY : Integer);

begin

Hide;

X := NewX;

Y := NewY;

Show

end;

Этот объект имеет только одно "собственное" поле Radius, и все поля данных, которые он унаследовал от объекта Point, т. е. поля X, Y, и Visible. Правила GetX и GetY наследуются от объекта Location без изменений.

Наличие нового поля Radius потребует изменений в методе Init для инициализации не только унаследованных полей, но и поля Radius. Вместо непосредственнго присваивания значений унаследованным полям X, Y и Visible, в методе Circle.Init используется унаследованный метод Point.Init. После вызова Point.Init, в теле Circle.Init выполняется присваивание полю Radius значения фактического параметра, переданного на месте формального параметра InitRadius.

Вместо того, чтобы “показывать” и “прятать” круг в целом, а не точка за точкой, используется процедура модуля Graph. В этом случае для объекта Cirсle понадобятся новые методы Show и Hide, которые заменяют аналогичные для объекта Point..

Вызов Graph.Circle в методе Circle.Show указывает на подпрограмму Circle в модуле Graph, а не на тип объекта Circle.

В определении объекта Circle также заменен метод MoveTo объекта Point, о чем свидетельствует спецификатор (префикс) объекта Circle перед идентификатором MoveTo. При этом замененный метод не использует поле Radius и в нем отсутствует вызов Graph.Circle для рисования круга, т. е. Circle.MoveTo полностью повторяет формулировку Point.MoveTo, что может вызвать некоторую растерянность и объясняется следующим.

Все методы, рассматриваемые до сих пор в связи с типами объектов Location, Point и Circle, являлись статическими. Термин "статические" (static) здесь используется применительно к методам, которые не являются "виртуальными" – virtual).

Особенности статических методов таковы: пока копия метода MoveTo не будет помещена в контекст объекта Сircle для замены метода MoveTo объекта Point, метод не будет выполнять нужные действия, если он вызывается из объекта типа Circle. При вызове для объекта Circle метода MoveTo объекта Point на экране будет передвигаться не круг, а точка. Только если объект Circle вызывает копию MoveTo, определенную как Circle.MoveTo круг будет “показан” и “спрятан” вложенными вызовами Show и Hide.

Последнее определяется способом компиляции статических методов. При компиляции методов объекта Point в коде метода Point.MoveTo используются вызовы Point.Show и Point.Hide в соответствии с описанием метода:

procedure Point.MoveTo(NewX, NewY : integer);

begin

Hide; {вызывает Point.Hide}

X := NewX;

Y := NewY;

Show; {вызывает Point.Show}

end;

Таким образом вызов Point.MoveTo предполагает вызовы Point.Show и Point.Hide. Если бы объект Circle наследовал метод объекта Point, последний исполнялся бы так, как был ранее откомпилирован. Вместо Circle.Show и Circle.Hide выполнялись бы Point.Show и Point.Hide и перемещалась точка, а не круг. При переопределении метода в его код включаются вызовы процедур Show и Hide, определенные в его контексте, то есть Circle.Show и Circle.Hide.

Логика “работы” компилятора при вызове статических методов такова: когда вызывается метод, компилятор сначала ищет метод с таким именем, определенный в пределах типа объекта. Поскольку методы с именами Init, Show, Hide, и MoveTo переопределены в объекте Circle, компилятор использует вызов одного из перечисленных методов. Если метод с таким именем не найден в пределах типа объекта, то компилятор переходит к типу непосредственного прародителя, и снова ищет указанный метод. При положительном исходе вызов метода потомка заменяется вызовом метода прародителя. В противном случае продолжается поиск вверх по дереву порождения. Отсутствие метода в корне дерева вызывает сообщение об ошибке, свидетельствующее о том, что такое правило в данной коллекции не определено.

При этом важно учитывать, что если метод прародителя вызывает другие методы, то эти методы также принадлежат прародителю, даже если у потомков эти методы переопределены.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]