13.3. Наследование

При помощи объекта типа ObjPos (см. рис. 13.1) определяется положение какого-либо символа в тексте на дисплее, но сам символ в нем не определен. Объявим объект с именем ObjSym, добавляющий символ и выполняющий определенные действия с ним (рис. 13.3).

| USES CRT; { в примере используется системный модуль CRT }

| TYPE

| ObjSym = OBJECT

| Line : Word; { номер строки с Sym }

| Col : Word; { номер столбца с Sym }

| Sym : Char; { поле-значение символа }

| PROCEDURE Init(init_line,init_col : Word;

| init_sym : Char);

| FUNCTION GetLine : Word; { опрос Line }

| FUNCTION GetCol : Word { опрос Col }

| PROCEDURE Print { вывод Sym }

| END;

| PROCEDURE ObjSym.Init; { инициализация полей объекта }

| BEGIN

| Line := init_line; { метод задания номера строки }

| Col := init_col; { метод задания номера столбца }

| Sym := init_sym { задание значения символа } END;

| FUNCTION ObjSym.GetLine : Word;

| BEGIN

| GetLine := Line { метод опроса номера строки }

| END;

Рис. 13.3

- 276 -

| FUNCTION ObjSym.GetCol : Word;

| BEGIN

| GetCol := Col

| { метод опроса номера столбца }

| END;

| PROCEDURE ObjSym.Print;

| BEGIN

| CRT.GotoXY(Col,Line);

| { процедура из библиотеки CRT }

| Write( Sym ) { вывод символа в позиции }

| END;

Рис. 13.3 (окончание)

Обратите внимание на то, что в задании нового объекта использовались поля данных и два метода GetLine и GetCol, идентичные полям и методам ранее описанного объекта ObjPos. Метод Init переписан заново, а поле Sym и, по сути, метод Print просто добавлены. Можно сказать, что более сложный объект, описывающий символ в тексте, унаследовал свойства и методы объекта-позиции. Методология ООП строится как раз на построении такого ряда объектов, в котором можно было бы проследить развитие и наследование свойств от простых структур к сложным.

Синтаксически наследование выражается следующим образом. В случае определения типа объекта, как производного от уже существующего, имя прародительского объекта заключается в круглые скобки после служебного слова OBJECT:

TYPE

ИмяОбъектаНаследника = OBJECT( ИмяОбъектаПрародителя )

НовыеПоляОбъектаНаследника;

НовыеМетодыОбъектаНаследника;

END;

Пример на рис. 13.3 по правилам ООП и Турбо Паскаля должен выглядеть, как показано на рис. 13.4 (на нем не показаны, но используются определения, введенные ранее на рис. 13.1).

Тип «наследник» иногда называется производным типом, а тип, от которого производится наследование («прародитель») — прародительским типом. Таким образом, отличие объекта от записи состоит не только в объединении полей и методов «под одной крышей», но и в способности объектов к наследованию. Поля и методы прародителя могут появляться в телах методов наследника, как если бы они были объявлены явно. На рис. 13.4 это иллюстрируется методом Init, который для инициализации полей

- 277 -

| USES CRT; { в примере используется системный модуль CRT }

| {*3десь должны быть определения, введенные на рис.13.1*}

| TYPE

| ObjSym = OBJECT( ObjPos ) { объявление наследования }

| Sym : Char; { поле-значение символа }

| PROCEDURE Init(init_line, init_col : Word;

| init_sym : Char );

| PROCEDURE Print { метод вывода символа }

| END;

| PROCEDURE ObjSym.Init;

| BEGIN

| ObjPos.Init( init_line, init_col ); {задание позиции }

| Sym := init_sym { задание значения символа }

| END;

| PROCEDURE ObjSym.Print;

| BEGIN

| CRT.GotoXY(Col, Line); {процедура из библиотеки CRT}

| Write( Sym ) { вывод символа в позиции }

| END;

Рис. 13.4

Line и Col, «по наследству» перешедших к объекту ObjSym, пользуется наследуемой процедурой ObjPos.Init.

Продолжая ряд наследования, можно ввести объект, описывающий символ совместно с его цветовым атрибутом. Для этого достаточно описать объект, производный от ObjSym и добавляющий поле данных для атрибута и методы его назначения или опроса. Такой объект будет третьим уровнем наследования, если считать от базового объекта ObjPos. Но можно объявить и объект того же уровня наследования по отношению к ObjPos, что и ObjSym. Определим, к примеру, объект «подстрока» (он пригодится в последующих примерах). Для задания подстроки надо указать координаты ее начала номер строки и столбца) и само содержимое подстроки, которое содержит в себе указание на ее длину. Можно создать объект типа ObjString, описывающий подстроку, как производный от объекта-позиции (рис. 13.5).

Процесс наследования является транзитивным: если тип объекта TypeB наследуется от типа объекта TypeA, а тип TypeC наследуется от TypeB, то тип объекта TypeC также считается наследником типа TypeA. Таким образом, можно получить иерархию объектов, связан-

- 278 -

| TYPE

| ObjString = OBJECT( ObjPos )

| SubSt : String; { поле-значение подстроки }

| PROCEDURE Init( init_line, init_col:Word;

| init_ss:String );

| PROCEDURE Print { вывод SubSt в позиции }

| END;

| PROCEDURE ObjString.Init; { инициализация полей объекта }

| BEGIN

| ObjPos.Init( init_tine, init_col ); {задание позиции }

| SubSt := init_ss { задание значения подстроки }

| END;

| PROCEDURE ObjString.Print;

| BEGIN

| CRT.GotoXY(Col, Line); { процедура из библиотеки CRT }

| Write( SubSt ) { печать подстроки в позиции }

| END;

Рис. 13.5

ных «родственными» отношениями. Как правило, основная часть работы по написанию объектно-ориентированных программ состоит в построении именно иерархий объектов.

При наследовании полей в производных типах уже нельзя объявлять их идентификаторы, определенные в одном из прародительских типов. Однако на методы это ограничение не распространяется. Производный объект может переопределять любой из методов, наследуемый от своих прародителей. Если описание метода в производном типе вводит тот же идентификатор для метода, что и описание метода в прародительском типе, то в этом случае ко всем последующим потомкам переходит переопределенный метод (пока он не будет заново переопределен). Следует отметить, что во всех прародительских типах действуют те методы, которые были определены изначально именно для них.

Несколько слов о «хорошем тоне» ООП. В случае, если в производном типе описывается новая процедура инициализации, в ней обычно вначале вызывается процедура инициализации непосредственного прародителя. Так удобно поступать еще и потому, что это самый естественный способ проинициализировать наследуемые поля предназначенным для этого методом.

- 279 -