Главная страница Случайная страница Разделы сайта АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Создание и уничтожение объектов
Object Pascal использует так называемую ссылочную объектную модель[3]. Это означает, что все объекты размещаются в памяти динамически, а объектные переменные фактически являются указателями на данные объекта в динамической памяти и имеют одинаковый размер (4 байта). Однако для доступа к данным объекта не используется символ разыменовывания ^ (записывается Man.fName, а не Man^.fName, хотя подразумевается именно второе). Для начального размещения объектов в динамической памяти служит особый вид методов, называемых конструкторами. Чтобы объявить метод как конструктор, используется ключевое слово constructor. Оно записывается вместо слова procedure при определении метода в классе и при реализации метода (конструктор не может быть функцией). Компилятор автоматически добавляет к телу конструктора код, выделяющий в динамической памяти участок для полей объекта и обнуляющий этот участок. Так как конструктор необходимо выполнить перед использованием объекта, то в тело конструктора обычно помещают операторы инициализации объекта, например, задание начальных значений для полей. Отметим, что Object Pascal допускает существование в классе нескольких конструкторов. Традиционное имя для конструктора – Create. Добавим конструктор в класс TPerson: type TPerson = class ... constructor Create; end;
constructor TPerson.Create; begin fAge: = 1; fName: = 'Person' end; Синтаксис вызова конструктора: имя-объекта: = имя-класса.имя-конструктора: Man: = TPerson.Create; Конструктор можно вызывать в виде имя-объекта.имя-конструктора, т. е. как обычный метод: Man.Create; Такой вызов означает простое выполнение тела конструктора (ре-инициализацию полей). Его можно применять только для тех объектов, которые уже размещены в памяти. Если объект не используется, то занимаемая им динамическая память должна быть освобождена. Для уничтожения объектов предназначены особые методы – деструкторы. Для объявления деструкторов используется ключевое слово destructor. Тело деструктора – подходящее место для финальных действий с объектом. Традиционное имя для деструктора – Destroy. Добавим в класс TPerson деструктор: type TPerson = class ... constructor Create; destructor Destroy; end;
destructor TPerson.Destroy; begin fAge: = 0; fName: = '' end; Теперь полный цикл работы с объектом Man выглядит следующим образом: Man: = TPerson.Create; // создание объекта Man.fName: = 'John Dow'; // работа с объектом Man.Destroy; // уничтожение объекта Деструктор можно вызвать только у инициализированного объекта. Попытка вызвать деструктор у неинициализированного объекта может привести к исключительной ситуации в работе программы. В качестве примера работы с конструкторами и деструкторами рассмотрим класс для представления структуры данных бинарное дерево целых чисел. Такое дерево хранит в каждом узле некий целочисленный вес, а так же ссылки (возможно пустые) на правое и левое поддерево. Реализуем в классе единственный метод для подсчёта веса всего дерева. type TBTree = class Weight: Integer; Left, Right: TBTree; function GetWeight: Integer; end;
function TBTree.GetWeight; begin Result: = Weight; if Left < > nil then inc(Result, Left.GetWeight); if Right < > nil then inc(Result, Right.GetWeight); end; Снабдим класс TBTree двумя конструкторами. Первый будет устанавливать вес узла, второй кроме этого будет инициализировать левое и правое поддеревья. Хотя эти два конструктора можно назвать по-разному, дадим им одинаковые имена и воспользуемся возможностью перегрузки подпрограмм: type TBTree = class ... constructor Create(W: Integer); overload; constructor Create(W: Integer; LTree, RTree: TBTree); overload; end;
constructor TBTree.Create(W: Integer); begin Weight: = W; end;
constructor TBTree.Create(W: Integer; LTree, RTree: TBTree); begin Weight: = W; Left: = LTree; Right: = RTree; end; Работа с классом TBTree может выглядеть так: var T: TBTree; ... T: = TBTree.Create(10); T.Left: = TBTree.Create(20); T.Right: = TBTree.Create(100, TBTree.Create(400), TBTree.Create(5)); Y: = T.GetWeight; // 10 + 20 + 100 + 400 + 5 Добавим в класс TBTree деструктор. Одно из правил ООП гласит: «Если объект во время работы самостоятельно резервировал динамическую память, она должна быть освобождена деструктором класса». Деструктор для класса TBTree будет выглядеть следующим образом: type TBTree = class ... destructor Destroy; end;
destructor TBTree.Destroy; begin if Left < > nil then Left.Destroy; if Right < > nil then Right.Destroy; end; Приведём полный пример консольного приложения с классом TBTree: program BinaryTree;
{$APPTYPE CONSOLE}
type TBTree = class Weight: Integer; Left, Right: TBTree; constructor Create(W: Integer); overload; constructor Create(W: Integer; LTree, RTree: TBTree); overload; function GetWeight: Integer; destructor Destroy; end;
constructor TBTree.Create(W: Integer); begin Weight: = W; end;
constructor TBTree.Create(W: Integer; LTree, RTree: TBTree); begin Weight: = W; Left: = LTree; Right: = RTree; end;
function TBTree.GetWeight; begin Result: = Weight; if Left < > nil then inc(Result, Left.GetWeight); if Right < > nil then inc(Result, Right.GetWeight); end;
destructor TBTree.Destroy; begin if Left < > nil then Left.Destroy; if Right < > nil then Right.Destroy; end;
var T: TBTree;
begin T: = TBTree.Create(10); T.Left: = TBTree.Create(20); T.Right: = TBTree.Create(100, TBTree.Create(1000), TBTree.Create(5)); writeln(T.GetWeight); T.Destroy; end.
|