Способы наследования и переопределения

Объект обладает важным свойством -наследование, которое позволяет при определении нового объекта-потомка использовать ранее определенный объект-предокили родительский тип. Тип TImage, задающий образец объекта, использоваться в программе самостоятельно не будет, однако он является предком целой иерархии объектов, например: строки, символа. Возьмем в качестве изображения символ и определим его тип, используя в качестве предка тип TImage. Мы хотим сохранить все поля предка, добавив лишь одно поле S, задающее конкретный символ. В этом случае в определении типа потомка необходимо сделать ссылку на имя родительского типа после слова Object:

type PSymbol = ^TSymbol; {указатель на объект – символ} TSymbol = object (TImage) S: char; end;

В этом случае в типе TSymbol неявно присутствуют все поля типа TImage. Аналогично переменной типа TSymbol или PSymbol доступны все методы из TImage, например:

var PS: PSymbol; begin New(PS); PS^.X := 1; PS^.Y := 2; PS^.S :='*'; writeln('координаты символа X,Y=', PS^.GetX: 5, PS^.GetY: 5); end;

Поля X, Y и методы GetX, GetY унаследованы от предка TImage, поле S определено в типе потомка TSymbol. Введение иерархии объектов позволяет более кратко описывать каждый объект-потомок, благодаря наследованию им всех свойств объекта родителя. Итак тип TSymbol наследует все поля и все методы родительского типа TImage. Однако очевидно, что не все методы предка подходят для манипуляций полями потомка. Например, процедура установки начальных значений Init должна определять кроме координат символа еще и сам символ. Кроме того, процедуры On, Off (включение/выключение изображения) и PrintImage (вывод изображения) целиком определяются типом объекта. Они будут разными для символа и строки, которые являются потомками объекта TImage.

Объектно-ориентированный подход позволяет определить новые методы для потомков со старыми именами методов родителя. Это свойство объектов называетсяпереопределением. Рассмотрим новое определение объекта TSymbol:

type PSymbol = ^TSymbol; TSymbol = object(TImage) S:char; {обрабатываемый символ} procedure Init(A,B:integer; C:char); procedure On; procedure Off; procedure PrintImage; end;

Объект TSymbol содержит поля X, Y, RX, RY, V, унаследованные от родительского типа TImage, собственное поле S, свои методы TSymbol.Init, TSymbol.On, TSymbol.Off, TSymbol.PrintImage и три унаследованных и не переопределенных метода Move, GetX, GetY.

Приведем тексты переопределенных процедур:

procedure TSymbol.Init(A,B:integer;C:char); begin TImage.Init(A,B); S:=C; end; procedure TSymbol.On; begin V:=TRUE; GotoXY(X,Y); {процедура из модуля CRT, устанавливающая курсор в позиции X,Y} write(S); end; procedure TSymbol.Off; begin V:=FALSE; GotoXY(X,Y); write(' '); end; procedure TSymbol.PrintImage; begin writeln('символ:',S); end;

Вызов метода осуществляется с использованием имени экземпляра объекта, например:

var TS1: TSymbol; TI1 – {экземпляры объектов} TI1: TImage; . . . TS1.Init(1,2,'*'); TI1.Init(1,1);

Отметим, что переопределять можно только методы (но не переменные), причем новый метод может иметь другие формальные переметы ( процедура Init). Новый метод "закрывает" одноименный метод в объекте-родителе.

Свойство наследования накладывает ограничения на имена полей: имена полей потомка не должны совпадать с именами полей в объекте-родителе.

Механизм наследования предоставляет широкие возможности по конструированию новых объектов, используя для их определения некоторые базовые типы, добавляя в них новые поля и переопределяя некоторые методы.

Для переменных объектного типа возможно присваивание значений экземпляра одного объекта экземпляру другого объекта в двух случаях: либо они имеют одинаковый объектный тип, либо они состоят в отношении наследования. В этом случае объекту-родителю присваивается значение объекта-потомка, например:

TI1 := TS1;

Присваивание осуществляется только для полей, являющихся общими для обоих типов.