Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП.doc
Скачиваний:
1
Добавлен:
14.04.2019
Размер:
181.25 Кб
Скачать

Иерархия типов Наследование реализации Проблемы наследования

Один модуль использует другой:

interface

implementation

interface

implementation

uses

Наследуем определение функции в первом модуле.

Вопрос: что наследуется?

Может наследоваться имя или interface, то есть это означает, что interface второго модуля более полный, чем первого, то есть это отношение пополнения интерфейса. Наследование интерфейса отражает естественный ход программирования как добавление новых имён. При этом возможны два случая: либо по умолчанию реализация не меняется, либо она меняется, но ссылается на предыдущую. С точки зрения семантики это означает доопределение, или уточнение, значения данного имени. Проще говоря, мы начинаем относиться к функциям и типам как к переменным.

Классический пример: x:=x+1;

Подобное последовательное переопределение значений имён характерно не только для программирования, но и любой классификации.

Животные

Рыбы Млекопитающие Птицы

Акула Карась Дельфин Слон Пингвин Петух

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

Как обычно, в случае древовидных иерархий разделим типы-предки и типы-потомки и определим отношения наследования между типами как пополнение интерфейса и уточнение семантики.

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

unit (модуль определения класса-потомка);

uses (модуль определения класса-предка);

interface

(имя класса потомка)=class (имя класса предка)

***********

end;

Любой класс наследуется от единого предка класса tObject (объект вообще).

Пример. Черепашья графика. Простая модель управления роботом-черепашкой, рисующем на дискретной сетке.

unit TurtleGraphicsUnit;

uses GridUnit;

interface

type

private

bPenUp: boolean;{состояние пера}

TurtleGraphicsClass=class(CellGridClass)

public

constructor Create (StartPosition: tPosition);

{Устанавливает начальное состяние сетки и положение черепашки на ней. Тем

самым реализация Create по умолчанию изменяется, перегружается. Методы

предка могут быть переписаны, но не удалены}

constructor Create (Position: tPosition).overload; {Указывает на то, что метод

предка переписан. Остальные

методы добавлены}

procedure PenUp; {поднимаем перо}

procedure PenDown; {опускаем перо}

{Переходим на заданное число шагов. Если перо опущено, оставляем след}

procedure Right(Step: integer);

procedure Left(Step: integer);

procedure Down(Step: integer);

procedure Up(Step: integer);

end;

Итак, у нас появляются два отношения между типами (модуль-класс), отношения использования и отношения наследования. В реализации класса GridUnit сы закрыли опцией private некоторые поля, стремясь скрыть реализацию от пользователя. На деле мы скрыли их от всех остальных модулей, что мешает эффективной реализации нашего класса (TurtleGraphicsUnit). Опция protected закрывает доступ к полям и методам класса для пользователя, но не для наследника.

Перепишем этот класс, в котором методы доступа к полям объявим так: те, что были private, объявим protected. Сами поля оставим private.

implementation

constructor TurtleGraphicsClass.Create(StartPosition: tPosition);

begin

inherited Create; {то есть ссылка на соответствующий метод класса-предка}

set CurrentPosition(StartPosition);

set CurrentColor(cRed);

set CurrentSetColor(cWhite);

end;