Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
TURBO_PASCAL.doc
Скачиваний:
4
Добавлен:
01.07.2025
Размер:
8.23 Mб
Скачать

13.2. Область действия полей объекта и параметр Self

Область действия (domain) полей данных объекта неявно распространяется на тела процедур и функций, реализующих методы этого объекта. В примере на рис. 13.1 метод Init (процедура) работает с полями Line и Col объекта типа ObjPos, обращение к которым не требует указания имени объекта. Можно сказать, что внутри методов объекта действует неявный оператор WITH. Следствием этого является то, что формальные параметры метода (если присутствуют) не могут совпадать по имени ни с одним из полей данных соответствующего объекта. {273}

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

VAR

ObjPosVar : ObjPos; { экземпляр объекта }

...

with ObjPosVar do { оператор присоединения }

begin

Init( 1,1); { имя экземпляра опущено }

...

Init( GetLine+1, GetCol+1 );

...

end; { with }

Всякий раз, когда вызывается метод какого-либо объекта, в него, кроме фактических параметров, передается невидимый параметр Self («свой», «внутренний»). Он указывает, какому объекту принадлежит метод. Так, метод Init из примера на рис. 13.1 воспринимается компилятором так, как если бы он был описан следующим образом:

PROCEDURE ObjPos.Init( init_line, init_col : Word );

BEGIN

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

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

END;

Компилятор автоматически обрабатывает параметр Self, поэтому не стоит использовать его явно. Исключением является случай, когда идентификаторы начинают «конфликтовать» в пределах методов. На рис. 13.2 показано, как, используя в методе объекта параметр Self, разрешить конфликт между полями самого объекта и формального параметра (записи).

TYPE

PosRec = RECORD { запись }

Line, Col : Word; { номера строки и столбца }

END;

ObjPos = OBJECT { объект }

Line, Col : Word; { номера строки и столбца }

PROCEDURE Init2( Pos : PosRec ); { метод }

END;

Рис. 13.2 {274}

PROCEDURE ObjPos.Init2( Pos : PosRec );

BEGIN

with Pos do begin { присоединение для записи Pos }

Self.Line:= Line; { Self развязывает одинаковые имена}

Self.Col := Col

end {with}

END;

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

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 {275}

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, который для инициализации полей {276}

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. Таким образом, можно получить иерархию объектов, связан-{277}

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

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

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

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

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