32. Объекты

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

Данные в объекте называются полями, а процедуры и функции - методами. Объектный тип описывается в виде:

TYPE имя типа=ОБЗЕСТ описание полей описание методов END;

Поля объектов описываются так же, как поля записей, а описание метода -это заголовок процедуры или функции. Сами методы располагаются в программе после описания объектного типа. В заголовке процедуры или функции указыва­ется ее составное имя: имя типа.имя метода. Все поля объекта непосредственно доступны в каждом из его методов, их не нужно передавать через список пара­метров. В программе можно описать любое количество переменных объектного типа. Принято называть объектом - объектный тип, а переменную такого типа -экземпляром объекта. Структура объекта похожа на структуру записи, и для об­ращения к полям и методам объектов также используется либо составное имя:

имя экземпляра объекта . имя поля/метода , либо оператор WITH имя экземпляра объекта, внутри которого можно записы­вать простые имена полей и методов. Экземпляры  одного и того же объекта можно присваивать друг другу.

ПРИМЕР 1. "Простой объект": Type ObjT1=OBJECT x:Real; n:Word; Function Power:Real; END;

Function ObjT1.Power:Real;

VAR i : Word; p : Real;

BEGIN p:=1; FOR i:=1 TO n DO p:=p*x; Power:=p; END; VAR O1_1,O1_2 : ObjT1;

BEGIN WITH O1_1 DO BEGIN x:=2; n:=4; END;

WITH O1_2 DO BEGIN x:=3; n:=3; END; WRITELN(O1_2.Power-O1_1.Power:4:1);

END.

Программа выведет: 11.0

Наиболее важным свойством объектов является механизм наследования. Объект может быть объявлен потомком ранее описанного объекта и унаследо­вать от объекта-родителя все его поля и методы. Объект потомок может также иметь собственные поля и методы, которых не было у объекта-родителя. Объект потомок описывается так: OБJECT(uмя родителя)

описание новых полей описание новых методов END; Экземпляру объекта-родителя можно присваивать экземпляр объекта-потом­ка, но не наоборот.

ПРИМЕР 2. "Наследование":

Type ObjT1=... ;

ObjT2=OBJECT(ObjT1) y:Real; Function RealPower:Real; END; ObjT3=OBJECT(ObjT2) Function Power10:Real; END;

Function ObjT1.Power...;

Function ObjT2.RealPower:Real; BEGIN RealPower:=Exp(y*Ln(x)); END; Function ObjT3.Power10:Real; BEGIN Power10:=Exp(y*Ln(10)); END;

VAR O1 : Objt1; O2 : ObjT2; O3 : ObjT3;

BEGIN WITH O3 DO BEGIN x:=2; y:=1/3; n:=5; END; O2:=O3; O1:=O3; WRITELN(O3.Power10-O2.RealPower+O1.Power:7:4);

END.

Программа выведет: 32.8945 = 101/3-21/3+25

Объект-потомок может заменять методы объекта-родителя на собственные методы с теми же именами. Такое свойство объектов называется полиморфиз­мом.

ПРИМЕР 3. "Полифорфизм":

Type ObjT1=... ; ObjT2=... ;

ObjT3=... ;

ObjT4=OBJECT(ObjT3) Function Power(t:INTEGER):REAL; END;

Function ObjT1.Power... Function ObjT2.RealPower... Function ObjT3.Power10... Function ObjT4.Power(t:Integer):Real;

VAR i : Word; p : Real; Minus : Boolean; BEGIN Minus:=t<0; p:=1;

FOR i:=1 TO ABS(t) DO p:=p*x;

IF Minus THEN Power:=1/p ELSE Power:=p;

END;

VAR O4 : ObjT4;

BEGIN O4.x:=2; WITH O4 DO WRITELN(Power(2)-Power(-2):5:2); END.

2 2

Программа выведет : 3.75 = 2 -2"

Некоторые из методов объекта могут быть виртуальными. При описании та­ких методов в объекте после заголовка процедуры или функции записывается конструкция VIRTUAL; Объект, содержащий хотя бы один виртуальный метод, должен иметь и специальный метод - конструктор. Конструктор полностью то­ждественен процедуре, но слово Procedure в нем заменяется на слово Constructor. Виртуальные методы присоединяются к объекту не на этапе компи­ляции, а только при вызове конструктора (при этом содержимое конструктора не имеет никакого значения, он может быть и пустым). Конструкторы не могут быть виртуальными. Невиртуальные методы называются статическими. Объек­ты-потомки могут заменять родительские виртуальные методы только виртуаль­ными, а родительские статические методы - только статическими. Если объект-потомок заменяет родительский виртуальный метод своим, то у нового метода должен быть точно такой же список параметров, как и у родительского. На ста­тические методы это правило не распространяется.

ПРИМЕР 4a. "Статические методы ":

Type TA = OBJECT

Procedure Out; Function Message:String; END;

TB = OBJECT(TA)

Function Message:String; END;

Procedure TA.Out; BEGIN WRITELN(Message); END; Function TA.Message:STRING; BEGIN Message:='TA'; END; Function TB.Message:STRING; BEGIN Message:='TB'; END;

VAR A:TA; B:TB;

BEGIN A.Out; B.Out; WRITELN(B.Message); END. Программа выведет : TA TA TB.

В Примере 4a метод Out родительского объекта TA собирается полностью; в частности, к нему подключается метод Message объекта TA. Замена метода Message в объекте TB уже никак не может повлиять на унаследованный этим объектом статический метод Out.

ПРИМЕР 4b. "Виртуальные методы":

Type TA = OBJECT

Procedure Out; Function Message:String; Virtual; Constructor Init; END;

TB = OBJECT(TA)

Function Message:String; Virtual; Constructor Init; Procedure TA.Out; BEGIN WRITELN(Message); END; Function TA.Message:STRING; BEGIN Message:='TA'; END; Function TB.Message:STRING; BEGIN Message:='TB'; END; Constructor TA.Init; BEGIN END; Constructor TB.Init; BEGIN END;

VAR A : TA; B : TB;

BEGIN A.Init; A.Out; B.Init; B.Out; END. Программа выведет : TA TB.

В примере 4b метод Message является виртуальным, это значит, что компи­лятор не подключает этот метод к процедуре Out до выполнения конструктора. Какая именно функция будет использоваться в качестве метода Message, после компиляции еще не известно. Выполнение оператора A.Init приводит к подста­новке вместо неопределенного виртуального метода Message конкретной функ­ции TA.Message. Если виртуальных методов в объекте несколько, эта операция выполняется для каждого из них при вызове конструктора. Аналогично при вы­зове B.Init виртуальный метод Message в экземпляре объекта Б будет заменен на функцию TB.Message всюду, где этот метод используется, в том числе и внутри метода Out. Использование в объектах виртуальныгх методов предполагает, что потомки данного объекта будут изменять эти методы. Если изменение метода не ожидается, то он объявляется статическим.

Экземпляры объектов можно размещать в динамической памяти. Для этого используется либо процедура New :

№у/(указатель на объект[,конструктор]); , либо функция New :

указатель на объект:=New(тuп объекта[,конструктор]);

Конструктор обязательно указывается для объектов, имеющих виртуальные методы, и задается своим простым именем. В динамически размещаемых объек­тах можно использовать специальный метод - деструктор. Деструктор - это про­цедура, в которой ключевое слово Procedure заменяется словом Destructor. Ди­намически размещенный объект уничтожается процедурой Dispose(<указатель на объект>[,<деструктор>]);

В деструкторе можно предусмотреть все необходимые действия по очистке памяти.

ПРИМЕР 5. "Динамические объекты ": Type MType=ARRAY[1..100] OF Word;

MPtrType=AMType; Type ObjType = OBJECT

n:Byte;

p:MPtrType;

Procedure Fill; Virtual;

Procedure Out; Virtual;

Constructor Make;

Destructor Crush;

END;

Type PObjType = AObjType;

Procedure ObjType.Fill; VAR i:Byte;

BEGIN FOR i:=l TO n DO pA[i]:=Random(l00); END;

Procedure ObjType.Out; VAR i:Byte;

BEGIN FOR i:=l TO n DO Write(pA[i]:4); WriteLn; END;

Constructor ObjType.Make; BEGIN New(p); END;

Destructor ObjType.Crush; BEGIN Dispose(p); END;

VAR X,Y:PObjType;

BEGIN X:=New(PObjType,Make);

With XA DO BEGIN n:=40; Fill;  Out; END;

New(Y);

With YA DO BEGIN Make; n:=20; Fill; Out; Crush; END;

Dispose(X,Crush);

Dispose(Y);