Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Создание динамических объектов




Для того чтобы сформировать динамический объект, надо объявить соот ветствующий тип OBJECT и указатель на этот тип. Например:

Type ObjName = Object  { - тип - ObjName }

. . .

End; 

PObjName = ^ObjName; { - тип - указатель на ObjName } { Объявление динамического объекта:

Var PI : PObjName; { - со ссылкой на тип - указатель на объект}

Р2 : ^ObjName; { - со ссылкой на тип - объект }

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

Простейший способ размещения и удаления из ОП таких динамических объектов:

New ( P1 ); New ( Р2 ); ... Dispose ( P1); Dispose ( P2 );

где P1 и Р2 - имена указателей на динамические объекты.

New может использоваться также в качестве функции, которая возвращает значение указателя. Например:

P1 := New ( PObjName );

где PobjName - имя типа указателя динамического объекта.

Обращение к переменной - экземпляру объекта с помощью указателя про­изводится в виде Р1^ или Р2^.

Вызовы методов производятся обычным способом. Например: Р1^.МЕТ2;

Если динамический объект содержит виртуальные методы, он должен ини­циализироваться с помощью вызова конструктора. Например:

Pl^.INIT; P2^.INIT;

Если конструктор не может разместить динамический объект в ОП, то он возвращает "пустой" указатель, например: PI = NIL.

Для работы с динамическими объектами, содержащими виртуальные мето­ды, Паскаль имеет процедуры NEW и DISPOSE с расширенными возможно­стями. Расширенный синтаксис процедуры New позволяет выделять из кучи ОП для объекта и инициализировать сам объект с помощью вызова его кон­структора. Для этого процедура New вызывается с двумя параметрами: име­нем указателя и именем конструктора. Например:

New (P1,INIT); New(P2,INIT);.

Параметр INIT выполняет вызов конструктора и инициализацию динами­ческого объекта.

Пример программы, использующей динамические объекты с виртуальным методом, приведен в листинге 6.

Удаление динамических объектов. Деструкторы

Динамическими могут быть объекты со статическими и виртуальными ме­тодами. Удаление динамических объектов может быть с помощью процедур Dispose или с помощью деструктора.

Подобно другим динамическим типам данных динамические объекты со статическими методами могут удаляться с помощью Dispose. Например:

Dispose ( P1 );.

Пример программы с динамическим объектом со статическими методами дан в листинге 5.

Листинг 5.Динамические объекты со статическими методами.

Program novirt;   Uses Crt; { Объявления: }
Type ObjName1 = object { - объекта-предка }

Fl1 : integer;

Procedure Met1;

Procedure Met2; End;

ObjName2 = object ( ObjName1 ) { - объекта-потомка }

Procedure Met2; End;

PobjName1 = ^ObjName1; {-тип - указатель на объект ObjName1 }

PObjName2 = ^ObjName2; { - " " " " ObjName2 }

{ --  Методы объекта ObjName1 -------  }

Procedure ObjName1.Met1; Begin

Met2; { - вызов только метода ObjName1.Met2 !!}

End;

Procedure ObjName1.Met2; Begin   FL1 := 12;

Writeln ( 'Работает метод ObjName1.Met2: Fl1 = ', FL1) End;

{ --   Методы объекта ObjName2 ------  }

Procedure ObjName2.Met2; Begin  FL1 := 34;

Writeln ( 'Работает метод ObjName2.Met2: Fl1 = ', FL1) End;

Var V1 : PobjName1;  { - динамический объект V1 } V2 : PObjName2;   { - "    " V2 }

{ ------ Основная программа----------- }

Begin  ClrScr;

Assign (Output, 'dnovirt.res'); Rewrite (output);

Writeln ('ДИНАМИЧЕСКИЕ ОБЪЕКТЫ, СТАТИЧЕСКИЕ МЕТОДЫ'); Writeln ('Работаем с VI - экземпляром типа предка');

New ( V1 ); { - создание динамического объекта V1 }

V1^.Met1; { - вызов метода ObjName1 .Met1; }

Vl1.Met2; { - " " ObjName1.Met2; }

Dispose ( V1 ); { - удаление объекта V1 }

Writeln ('Работаем с V2 - экземпляром типа потомка');

New ( V2 ); { - создание динамического объекта V2 }

V2^.Met1; { - вызывает ВСЕГДА метод ObjName1.Met2,

а не ObjName2.Met2 }

V2^.Met2; { - вызов метода ObjName2.Met2; }

Dispose ( V2 ); { - удаление объекта V2 }

Close (Output);

End.

Для освобождения ОП динамических объектов с виртуальными методами используются особые методы - деструкторы. В качестве их имен рекомендует­ся употреблять имя Done. Они предназначены для выполнения завершающих действий программы. Деструктор размещается вместе с другими методами объекта в определении типа и оформляется так же, как обычный метод-процедура, но слово PROCEDURE заменяется словом DESTRUCTOR. Например: Destructor TObjl.Done;.

Вызов деструктора (Done) вне процедуры Dispose не приведет к автома­тическому освобождению ОП, занимаемой экземпляром объекта, т. е. недо­пустимо Р1^.Done;.

Для корректного освобождения ОП, которую реально занимает экземпляр динамического объекта с поздним связыванием, деструктор надо вызывать с помощью расширенного типа процедуры Dispose. Он имеет 2 параметра: имя указателя на объект и имя деструктора. Например:

Dispose ( PI,Done);

где Done - имя деструктора объекта, на который указывает Р1.

Деструктор выполняется как обычный метод. Когда будет выполнено по­следнее его действие, если объект содержит виртуальные методы, то деструк­тор производит поиск размера объекта в ТВМ и передает его процедуре Dispose, которая и освобождает правильное количество байт, независимо от того, указывал ли Р1 на тип предка или потомка.

Метод деструктора может быть и пустым, так как основная информация содержится не в теле деструктора, а связана с его заголовком, содержащим слово Destructor.

Деструктор потомка последним своим действием должен вызывать соот­ветствующий деструктор своего непосредственного предка, чтобы освободить ОП всех наследуемых указателей объекта. Например:

Destructor Tobj1.Done;


Begin

. . . INHERITED Done;

End;

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

Термин "полиморфный" означает, что компилятор, строя код объекта, во время компиляции, "не знает", какой тип объекта будет в действительности использован. Единственное, что он "знает", - это то, что объект принадлежит иерархии объектов, являющихся потомками указанного типа предка. Размеры различных объектов иерархии могут быть разные. Информация о размере удаляемого объекта становится доступной, для деструктора из ТВМ в момент удаления экземпляра объекта. ТВМ любого объекта доступна через параметр Self, содержащий адрес ТВМ, который передается деструктору при его вызове.

Деструктор может объединять удаление объекта с другими действиями, необходимыми для корректного удаления. Например, при удалении динамиче­ского объекта может понадобиться не только освобождение занимаемой им ОП. Объект может содержать указатели на динамические объекты или свя­занные структуры (стеки, очереди, списки), которые надо удалить в опреде­ленном порядке. Все операции для удаления динамического объекта должны объединяться в один метод, чтобы объект мог быть уничтожен с помощью одного вызова. Например: Objl .Done; или Dispose ( Pi, Done );.

Для одного и того же типа объекта может быть несколько деструкторов. Деструкторы можно наследовать. Они могут быть статическими или вирту­альными. Например: Destructor Done; Virtual;

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

Деструкторы работают с динамическими объектами. Но применение дест­руктора к статическим объектам не является ошибкой и не приведет к некор­ректной работе программы.

Пример программы с динамическим объектом с виртуальными методами и с использованием деструктора приведен в листинге 6.

Листинг 6.Динамические объекты с виртуальным методом.

Program Dvirt;   {$F+,R+} Uses Crt;

Type     ObjName1 = object { - тип объекта-предка }

Fl1 : integer;

Constructor Met1; {- конструктор типа ObjName1 }

Destructor Done; Virtual; {- деструктор типа ObjName1 } Procedure Met2; Virtual; End;

ObjName2=object (ObjName1) {-тип потомка ObjName1 ) Procedure Met2; Virtual;

Destructor Done; Virtual; {-деструктор типа ObjName2 } End;

PobjName1 = ^ObjName1; {- тип - указатель на объект ObjName1}
PObjName2 = ^ObjName2; { -" " "  ObjName2 }

{      Методы объекта ObjName1    }

Constructor ObjName1.Met1; Begin

Met2; {- вызов Met2 из конструктора }

End;

Destructor ObjName1.Done; Begin

Writeln ('Освобождается ОП объекта типа ObjName1'); End;

Procedure ObjNamel.Met2;

Begin Fl1 := 12;

Writeln ('Работает метод ObjName1.Met2: Fl1= ', Fl1) End;

{     Методы объекта ObjName2 --    }

Procedure ObjName2.Met2;

Begin Fl1 := 34;

Writeln ('Работает метод ObjName2.Met2: Fl1 = ', Fl1) End;

Destructor ObjName2.Done; Begin

Writeln ('Освобождается ОП объекта типа ObjName2'); End;

Var V1 : PobjName1; { - динамический объект V1 }

V2 : PObjName2; { - "   " V2 }

{ --------  Основная программа --------- }

Begin ClrScr;

Assign (Output, 'Dvirt.res'); Rewrite (output);

Writeln ('ДИНАМИЧЕСКИЕ ОБЪЕКТЫ, ВИРТУАЛЬНЫЕ МЕТОДЫ' ); Writeln ('Работаем с V1 - экземпляром типа предка');

{Вызывается конструктор Met1 для экземпляра V1 - предка:}

New (V1,Met1); {- создание динамического объекта V1 }
V1^.Met2;       { - вызов метода ObjName1.Met2; }

{ Удаление объекта - только с помощью Dispose и Done: } Dispose (V1,Done); {- удаление объекта V1 деструктором

ObjName1.Done }

Writeln ('Работаем с V2- экземпляром типа потомка');

{Вызывается конструктор Met1 для экземпляра V2 - потомка V1:}
New ( V2, Met1 ); { - создание динамического объекта V2 }
V2^.Met2;    { - вызов метода ObjName2 .Met2; }

{ Удаление объекта - только с помощью Dispose и Done: } Dispose (V2,Done); { - удаление объекта V2 деструктором

ObjName2.Done}

Close (Output);

End.

Общие правила использования конструкторов и деструкторов: Constructor - для виртуальных методов, для создания ТВМ при исполь­зовании статических и динамических объектов.

Destructor - для освобождения ОП динамических объектов, содержащих виртуальные методы.





Контрольные вопросы

1. Что такое объектно-ориентированное программирование? Каковы его особенности и область применения?

2. Назовите свойства объектов.

3. Что такое инкапсуляция? Как объявить объект?

4. Что такое наследование и переопределение, предок, потомок? Как объявить объ­ект-потомок?

5. Что такое полиморфизм? Как переопределить статический, виртуальный методы?

6. Как создать, удалить динамический объект?

7. Что такое конструктор, деструктор? Когда надо их использовать?










Последнее изменение этой страницы: 2018-05-10; просмотров: 275.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...