Удаление динамических объектов. Деструкторы
Динамическими могут быть объекты со статическими и виртуальными методами. Удаление динамических объектов может быть с помощью процедур 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. Что такое конструктор, деструктор? Когда надо их использовать?
Дата добавления: 2019-12-09; просмотров: 710;