загрузка...
-->
Конструктори і деструктори PDF Печать E-mail

Конструктори і деструктори

Конструктори і деструктори є спеціалізованими формами методів.  Використовувані в  зв'язку  з  розширеним  синтаксисом стандартних  процедур  New і Dispose,  конструктори і деструктори мають здатність розміщення і видалення  динамічних  об'єктів. Крім того, конструктори мають можливість виконати необхідну ініціалізацію об'єктів, що  містять віртуальні методи. Як і всі інші методи,  конструктори і деструктори можуть успадковуватися, а об'єкти можуть містити будь-яке число конструкторів і  деструкторів.
Конструктори використовуються  для ініціалізації знову створених об'єктів. Звичайно ініціалізація ґрунтується на значеннях, переданих  конструктору як параметри.  Конструктор не може бути віртуальним,  тому що механізм диспетчеризації віртуального методу залежить від конструктора, що першим зробив ініціалізацію об'єкта.
Приведемо кілька прикладів конструкторів:
constructor Field.Copy(var F: Field);
begin
Self := F;
end;
constructor Field.Init(FX, FY, FLen: integer; FName: string);
begin
X := FX;
Y := FY;
GetMem(Name, Length (FName) + 1);
Name^ := FName;
end;
constructor TStrField.Init(FX, FY, FLen: integer; FName:string);         
begin
inherited Init(FX, FY, FLen, FName);
Field.Init(FX, FY, FLen, FName);
GetMem(Value, Len);
Value^ := '';
end;

Головною дією  конструктора породженого (дочірнього) типу, такого як зазначений вище TStrField.Init,  майже завжди є виклик відповідного  конструктора  його  безпосереднього        батька  для ініціалізації наслідуваних полів об'єкта.  Після виконання цієї процедури, конструктор інніціалізує поля чи об'єкта, що належать тільки породженому типу.
Деструктори ("збирачі сміття") є протилежностями конструкторів і використовуються для очищення об'єктів  після  їхнього  використання. Звичайно очищення складається з видалення всіх полів-покажчиків в об'єкті.
Примітка: Деструктор може бути віртуальним і часто є таким. Деструктор рідко має параметри.
Приведемо кілька прикладів деструкторів:
destructor Field.Done;
begin
FreeMem(Name, Length (Name^) + 1);
end;
destructor StrField.Done;
begin
FreeMem(Value, Len);
Field.Done;
end;

Деструктор дочірнього  типу,   такий   як   зазначений вище TStrField.Done, звичайно  спочатку  видаляє  введені в породженому типі поля чи вказівника,  а потім як останню дію викликає відповідний збирач деструктор безпосереднього батька для видалення успадкованих полів-вказівників об'єкта.
Відновлення помилок конструктора
Borland Pascal  дозволяє встановити функцію обробки помилки області, що динамічно розподіляється.  Ця функціональна  можливість впливає на спосіб роботи конструкторів об'єктного типу.
За замовчуванням,  коли для динамічного екземпляра об'єкта не вистачає пам'яті, виклик конструктора, що використовує розширений синтаксис стандартної процедури New,  генерує помилку етапу виконання 203. Якщо ви установили функцію обробки помилки області, що динамічно розподіляється, що замість стандартного результату функції 0 повертає 1,  коли виконати запит неможливо, виклик конструктора через New повертає nil (замість переривання програми).
Код, що виконує  розподіл пам'яті й ініціалізацію  поля чи таблиці віртуальних методів (VMT) динамічного екземпляра об'єкта є частиною послідовності виклику конструктора. Коли керування передається на оператор begin операторної  частини  конструктора, пам'ять для екземпляра вже виділена, і він інніціалізований. Якщо виділення пам'яті завершується невдало, і якщо  функція обробки помилки області, що  динамічно розподіляється, пам'яті повертає 1, конструктор пропускає виконання операторної частини  і повертає значення nil. Таким чином, вказівник, заданий у виконуваному конструктором виклику New, встановлюється в nil. Коли керування передається на  оператор begin операторної частини конструктора, для екземпляра об'єктного типу забезпечується успішне виконання пам'яті й ініціалізація. Сам конструктор може спробувати розподілити динамічні перемінні для ініціалізації полів-вказівників в екземплярі, однак, такий розподіл може завершитися невдало. Якщо це відбувається, правильно побудований конструктор повинний скасовувати всі успішні розподіли і, нарешті, звільняти виділену для екземпляра об'єкта  пам'ять, так що результатом може стати покажчик nil. Для виконання такого "скасування" Borland Pascal реалізує стандартну процедуру Fail, що не вимагає  параметрів і може викликатися тільки з конструктора. Виклик Fail приводить до того, що конструктор буде звільняти  виділену для динамічного екземпляра пам'ять, що була виділена перед входом у конструктор, і для вказівки невдачі повертає покажчик nil. Коли пам'ять для динамічних екземплярів виділяється за допомогою розширеного синтаксису New, що в результаті видає значення nil у заданому змінній-вказівник вказує, що операція завершилася невдало. На жаль, не існує такої змінної-вказівник, котру можна перевірити після побудови статичного екземпляра або  при виклику наслідуваного конструктора. Замість цього Borland Pascal дозволяє використовувати конструктор у виді  булевської функції: значення, що повертається, True указує на успішне виконання, а значення False - не неуспішне виконання через виклик у конструкторі Fail. На диску можна знайти дві програми - NORECVER.PAS і RECOVER.PAS. Обидві програми реалізують два простих об'єктних  типи, що містить вказівники. Перша програма не містить відновлення помилок конструктора. Програма RECOVER.PAS демонструє, як можна переписати вихідний код для реалізації відновлення помилки. Помітимо, що для скасування успішного виділення пам'яті перед викликом Fail для кінцевого неуспішного виконання використовуються відповідні  деструктори   в  Base.Init і Derived.Init. Відмітимо  також, що в Derived.Init виклик Base.Init утримується всередині виразу, так що можна перевірити успішність виконання наслідуваного конструктора.

 

Яндекс.Метрика >