Pull to refresh

Об «очевидном» и полезном или создание и уничтожение объектов Delphi

Reading time2 min
Views7K
Когда читаешь о той или иной реализации механизмов ООП, то весьма забавно видеть, как та или иная конкретная особенность конкретного языка или библиотеки называется «очевидной». Особенно выделяется в этом отношении описание ООП в C++, в котором по факту реализация одна из самых непрозрачных и запутанных.
Так вот, я ничего не буду писать про очевидность, а расскажу про способ облегчить себе жизнь в критических точках жизненного цикла объектов, используя не «очевидные», но весьма полезные особенности реализации ООП в Delphi.


Обработка невозможности завершить создание объекта в конструкторе


Если конструктор хранит свои данные только в полях объекта, то решение элементарно — достаточно возбудить исключение. RTL Delphi сама его перехватит, вызовет деструктор, высвободит занятую память и возбудит исключение повторно.
Соответственно, если часть данных для конструирования хранится в глобальных переменных, то достаточно использовать обычный блок try..except с повторным возбуждением исключения.
Отсюда выводятся два требования к деструкторам: не провоцировать исключения, что означает не пытаться заниматься чем-либо, кроме освобождения ресурсов (например, сохранением настроек) и обязательно поддерживать…

Удаление частично инициализированного объекта


В Delphi это не представляет никаких трудностей, так как любой объект еще до передачи управления конструктору инициализируется нулями. Соответственно, в деструкторе достаточно корректно обрабатывать нулевые значения, в чем сильно помогает процедура FreeAndNil, которая освобождает объект, только если ссылка на него уже не nil.

Порядок вызова конструкторов


В Delphi он не имеет значения. Можно вызывать конструкторы предка, другие конструкторы того же класса точно так же, как и обычные методы или не вызывать ничего — так что если надо использовать инициализацию предка, то забывать ее вызвать не рекомендуется, зато и проблем сделать что-то до или вместо вызова конструктора предка нет никаких.

Вызов виртуальных методов в конструкторе


Так как в Delphi объект сразу инициализируется конечной ссылкой на VMT, то никакой разницы между вызовами виртуальных методов из конструктора от прочих вариантов нет.

Виртуальные конструкторы и ссылки на класс


В Delphi конструкторы могут быть виртуальными. Смысл такой особенности — возможность создания объектов с неизвестным на этапе компиляции классом без необходимости реализации фабрики. С этой целью используется переменные со ссылкой на класс (а не объект!), для которых и можно вызвать виртуальный конструктор, получив экземпляр соответствующего класса или его потомка, в зависимости от значения ссылки.

Автоматическое управление временем жизни объекта


Если объект реализует тот или иной явно заданный интерфейс, то его можно привести к ссылке на этот интерфейс, используя присваивание или операцию as. В этом случае Delphi будет сама генерировать вызовы методов IUnknown, что позволяет не запрашивать интерфейсы и не удалять объекты явно.

Итоги


С одной стороны, все вышеперечисленное должен знать каждый разработчик; с другой — я встречал не так уж мало программистов со стажем, изобретающих велосипеды только от незнания особенностей реализации своего рабочего инструмента. Надеюсь, что эта статья немного поможет. Из полезных особенностей реализации ООП в Delphi осталась нерассмотренной поддержка делегирования реализации интерфейсов, но это тема для отдельной статьи.
Tags:
Hubs:
Total votes 56: ↑37 and ↓19+18
Comments44

Articles