Конструкторы и деструкторы в Delphi
Конструкторы и деструкторы отвечают за существование объекта в памяти, т.е. выделяют память для экземпляра класса, затем и освобождают ее.
Конструктор — это специальный вид подпрограммы, присоединенный к классу. Его на-значение — создавать представителей (экземпляры) класса. Он ведет себя как функция, которая возвращает ссылку на вновь созданный экземпляр класса, т.е. на объект. Одновременно выделяется память для хранения значений полей экземпляра класса.
Деструктор — это специальная разновидность подпрограммы, присоединенной к классу. Его назначение заключается в уничтожении экземпляра класса, т.е. объекта и освобождении памяти, выделенной под экземпляр.
Синтаксис объявления конструкторов и деструкторов:
Type
<имя класса>=Сlass[{Имя родительского класса>)]
. . .
Constructor Имя конструктора>[(<параметры>)]; [Override;]
Destructor <имя деструктора>[(<параметры>)}; [Override;]
End;
Примечания:
• Объявляются конструкторы и деструкторы, как правило, в разделе Public класса.
• В классе может быть объявлено несколько конструкторов, однако чаще бывает один конструктор. Общепринятое имя для единственного конструктора Create.
• В одном классе может быть объявлено несколько деструкторов, но чаще бывает один деструктор без параметров (всегда!) с именем Destroy.
• За объявлением деструктора по имени Destroy следует указывать ключевое слово-директиву Override, разрешающее выполнение предусмотренных по умолчанию действий для уничтожения экземпляра объекта, если при его создании возникла какая-либо ошибка. Фактически Override переопределяет метод предка
• Метод Free так же удаляет (разрушает) экземпляры класса, предварительно проверяя их на Nil.
Реализация конструкторов
В задачу конструктора входит создание экземпляра класса и выполнение операторов, содержащихся в его теле. Назначение кода внутри конструктора — инициализировать только что созданный экземпляр объекта. Синтаксис реализации конструктора:
Constructor <имя класса>.<имя конструктора>[(<параметры>}};
[<блок объявлений>}
Begin
<Исполняемые операторы>
End;
Реализация наследуемых конструкторов.
Constructor <имя класса>.<имя конструктора>[(<параметры>)];
[<блок объявлений>}
Begin
Inherited <имя конструктора>[(<параметры>)};
<инициализация собственных полей>
End;
Примечания:
• Следует убедиться, что для каждого поля в конструкторе предусмотрен оператор присвоения, и что все поля переходят из неопределенного состояния в какое-то конкретное, предусмотренное по умолчанию, хотя и известно, что транслятор сам выполнит инициализацию нулевыми значениями (», Nil, False — для других полей). Для неклассовых полей такая инициализация вполне допустима, поскольку позволяет их использовать в дальнейшем.
• Для вызова наследуемого конструктора следует использовать ключевое слово Inherited, которое фактически обеспечивает доступность перекрытого метода. Сила оператора в том, что он вызывает старое, а затем возвращается к новому.
• Как правило, следует вызывать подходящий наследуемый конструктор в первом исполняемом операторе.
• Только, если у пользовательского класса нет новых полей, можно не создавать для него конструктор.
• Хотя в объявлениях конструкторов и не указывается тип возвращаемого результата, и они выглядят, как объявления процедур, конструкторы используются скорее как функции, а не как процедуры. Можно сказать, что конструктор является неявной функцией — он возвращает нового представителя того класса, который использовался при его вызове. Нет необходимости в явном виде задавать тип возвращаемого результата, поскольку этот тип и так известен на момент вызова — это тип использованного в вызове конструктора класса.
• Внутри конструктора отсутствует и явное присвоение возвращаемого значения. Такое возможно, поскольку он всегда возвращает ссылку (адрес) на вновь созданный и инициализированный экземпляр класса.
• Начиная с класса TComponent конструктор Create стал виртуальным и при его переопределении необходимо указывать слово-директиву Override.
Реализация деструкторов
Деструктор уничтожает экземпляр класса, который был использован при его вызове, автоматически освобождая любую динамическую память, которая ранее была зарезервирована конструктором, закрывает файлы и т.п. операции. Программист ответственен за вызов деструкторов для всех экземпляров класса, если были зарезервированы подчиненные объекты.
Синтаксис реализации деструктора:
Destructor <имя класса>.<имя деструктора>[(<параметры>)];
[<блок объявлений>]
Begin
<исполняемые операторы>
End;
Реализация наследуемых деструкторов
Если использовать механизм наследования деструкторов, то можно упростить задачу уничтожения экземпляров класса, таким образом, чтобы каждый раз заботиться лишь об уничтожении тех полей, которые были добавлены в данном классе. Всю работу по очистке наследуемых полей можно возложить на наследуемые деструкторы. Для вызова наследуемого деструктора необходимо используется ключевое слово Inherited.
Синтаксис объявления наследуемого деструктора следующий:
Destructor <имя класса>.<имя деструктора>[(<параметры>)};
[<блок объявлений>]
Begin
<уничтожение собственных полей>
Inherited <имя деструктора>[{<параметры>)];
End;
Примечания:
• Внутри деструктора есть доступ не только к обычным идентификаторам, но и к полям экземпляра класса, инкапсулированным при его определении.
• Исполняемые операторы деструктора должны позаботиться обо всех операциях очистки, необходимых для уничтожения экземпляра класса. Код деструктора должен уничтожить все внутренние экземпляры объектов и освободить динамическую память, которая была зарезервирована во время существования экземпляра класса. Однако нет необходимости явно устанавливать в нулевые значения поля прямого доступа.
• Необходимость в объявлении деструкторов с параметрами возникает очень редко. Обычно все, что нужно сделать деструктору — уничтожить экземпляр класса, и вся необходимая для этого информация и так доступна ему.
• Если у класса нет полей косвенного доступа, то деструктор можно не создавать для такого пользовательского класса.
Вызов конструкторов
Для того чтобы вызвать конструктор, необходимо правильно объявить и определить класс. Объявление класса должно быть доступно, т.е. он должен находится в области видимости из того места, где конструктор будет вызываться.
Если в пользовательском классе не определен конструктор, то по умолчанию будет использоваться конструктор, унаследованный от класса-потомка. В любом случае у всех объектов есть доступ к конструктору Create, определенному в классе TObject.
Определение класса создает активную структуру, способную создавать представителей этого класса. Объекты, которые создаются с помощью определения класса, способны хранить ссылки на вновь создаваемые объекты.
Var <имя объекта>: <имя класса>; // Объявление переменной -указателя
Begin
<имя объекта>:=<имя класса>.<имя конструктора>[(<параметры>)];
• Если вызвать конструктор от имени объекта, то новый объект не будет создан (память не выделяется), но будут выполнены операторы, указанные в коде конструктора.
• Конструктор может также вызываться с помощью переменной типа указателя на класс.
[asd2]
Вызов деструкторов
Деструкторы вызываются точно так же, как и большинство других методов класса — через его действующий экземпляр.
Синтаксис вызова конструктора следующий:
<имя объекта>.<имя деструктора>[(<параметры>)];
Примечания:
• После вызова деструктора объект становится недоступен. Целесообразно присваивать объекту значение Nil сразу после его уничтожения, чтобы в дальнейшем можно было бы проверить его существование.
• Не следует вызывать деструкторы непосредственно. Вызов метода Free, наследуемого от TObject.Free, сравнивает указатель экземпляра со значением Nil перед тем, как вызвать деструктор Destroy.
Вызовы конструкторов и деструкторов визуальных компонентов Delphi. Любой компонент, попавший в ваше приложение при визуальном проектировании, включается в определенную иерархию объектов, которая замыкается на форме (класс TFonn). Поэтому вызов конструкторов и деструкторов всех компонентов формы производится автоматически при инициализации и удалении формы, незримо для программиста.
Сами формы создаются и уничтожаются приложением — глобальным объектом с именем Application. В файле-проекте с расширением *.Dpr можно увидеть вызов конструктора формы в виде строки:
Application.CreateForm(TForml, Fonnl);
Динамическое создание объектов. Пользователь может создать объект и программным путем:
Var Mem: TMemo;
Begin
Mem:=TMemo.Create(Self); // Создание экземпляра класса TMemo
Mem.Parent:=Self; // Form1 указывать не обязательно
Mem.Name:=’TmpMem’; // Присвоение имени компоненту
FindComponent(‘TmpMem’).Free; // Удаление компонента