Анализ структуры и разрушения в Delphi
1 объектная модель в Delphi: 2
1.1 Что означает имя объекта? 2
1.2 Где хранятся объекты? 2
1.3 Что хранится в объекте? Как они хранятся?
2 Конструктор и создание объекта 5
2.1 Что такое конструктор? («Специальный» метод класса) 5
2.2 Весь процесс создания объекта 5
2.3 Альтернативное использование конструкторов (с использованием ссылок классов для реализации полиморфизма конструкторов) 6
3 Деструктор и разрушение объект 7
3.1 Что такое деструктор («естественно» виртуальный метод) 7
3.2 Весь процесс разрушения объектов 7
3.3 Уничтожить, бесплатно, freeandnil, использование выпуска и разница 7
4 VCL Construction & Destructuring Architecture 8
5 Правильно используйте конструкторы и деструкторы 9
Анализ структуры и разрушения в Delphi
Аннотация: Благодаря изучению VCL/RTL, в этой статье анализируется механизм реализации конструкторов и деструкторов и архитектуру объектов в VCL, и объясняет, как правильно создавать и освободить объекты.
Ключевые слова: построить, разрушать, создавать объекты, уничтожить объекты, кучу, стек, полиморфизм.
Автор: Majorsoft
вопрос
Каков механизм реализации конструкторов и деструкторов в Delphi? Как правильно создать и выпустить объекты?
Решение
Как правильно использовать конструкцию и разрушение, мы сталкиваемся с использованием Delphi. Следующим является понимание механизма реализации конструкторов и деструкторов посредством изучения исходного кода VCL/RTL.
1 объектная модель в Delphi:
1.1 Что означает имя объекта?
В отличие от C ++, имя объекта (также называемое переменной) в Delphi представляет ссылку объекта и не представляет сам объект, который эквивалентен указанию на объект, который называется «Справочная модель объекта». Как показано на рисунке:
Obj (имя объекта) фактический объект
Адрес записи VMT
Данные члены
Рисунок 1 Имя объекта относится к объекту в памяти
1.2 Где хранятся объекты?
Каждое приложение делит память, выделенную ему, чтобы столкнуться с четырьмя областями:
Область кода
Глобальная область данных
Область кучи
Площадь стека
Рисунок 2 Программное пространство памяти
Область кода: хранить код программы в программе, включая все коды функций
Глобальная область данных: хранит глобальные данные.
Область кучи: также известная как «область свободного хранения», в которой хранятся динамические данные (включая объекты и строки в Delphi). Область - это весь жизненный цикл применения до тех пор, пока не будет вызван деструктором.
Область стека: также известная как «Область автоматического хранения» для хранения локальных данных в программе. Прицел находится внутри функции, и система немедленно перерабатывает пространство стека после вызова функции.
В C ++ объекты могут быть созданы в куче или в стеке или в глобальных данных. В Delphi все объекты построены на области хранения кучи, поэтому конструктор Delphi не может быть вызван автоматически, но должен вызывать самим программистом (перетащите компонент в дизайнере, а объект создается Delphi). Следующая программа объясняет разницу между созданием объектов в Delphi и C ++:
В Delphi:
Процедура CreateObject (var foobjref: tfooobject);
Начинать
Foobjref: = tfooobject.create;
// Вызван программистом, после того, как процедура называется, объект все еще существует.
Foobject.caption = 'Я создан в стеке createObject ()';
Конец;
И в C ++:
Tfooobject createObject (void);
{
Tfooobject foobject; // Создание локальных объектов
// static tfooobject foobject; // Создать статический локальный объект
// Объект автоматически создается путем вызова конструктора по умолчанию, и объект создается в стеке функций в настоящее время.
Foobject.caption = 'Я создан в стеке createObject ()';
вернуть foobject;
// объект копируется при возвращении, а оригинальный созданный объект будет автоматически уничтожен после завершения функционального вызова}
Tfooobject foobject2; // Создать глобальный объект.
void main ();
{Tfooobject* pfooobject = new tfooobject;
// Создать объект кучи. После того, как функция вызвана, объект все еще существует и не нуждается в копировании. }
1.3 Что хранится в объекте? Как они хранятся?
В отличие от C ++, объекты в Delphi хранят только входные адреса элементов данных и таблицы виртуальных методов (VMT), но не хранят методы, как показано на рисунке:
Объект виртуальный метод сегмент кода таблицы
Адрес VMT
Имя: строка
Ширина: целое число;
CH1: Чар;
…
Proc1
Func1
…
проведенный
Funcn
…
Рисунок 3 Структура объекта ...
Может быть, у вас есть несколько вопросов о приведенном выше утверждении, см. Следующую процедуру:
Tsizealigntest = class
Частный
я: целое число;
CH1, CH2: Чар;
J: целое число;
публичный
Процедура Showmsg;
Процедура kirlmtd;
конец;
memo1.lines.add (inttoStr (sizetest.instancesize)+': eNtescessize');
memo1.lines.add (inttoStr (Integer (sizetest))+'<-start addr');
memo1.lines.add (inttoStr (integer (@(sizetest.i)))+'<-sizetest.i');
memo1.lines.add (inttoStr (integer (@(sizetest.ch1)))+'<-sizetest.ch1');
memo1.lines.add (inttoStr (integer (@(sizetest.ch2)))+'<-sizetest.ch2');
memo1.lines.add (inttoStr (integer (@(sizetest.j)))+'<-sizetest.j');
Результаты показывают:
16: EnceSicesize
14630724 <-Start Addr
14630728 <-sizetest.i
14630732 <-sizetest.ch1
14630733 <-sizetest.ch2
14630736 <-sizetest.j
Участник данных и адрес записи VMT занимают 16 байтов!
Итак, где хранятся функции участника? Поскольку Delphi основан на RTL (библиотека типа времени), все функции членов хранятся в классе. Итак, как найти адрес записи функции участника? Для статических функций эта работа выполняется компилятором. на этот раз). Должен существовать в это время.
Уведомление
Как упомянуто выше, все функции членов хранятся в классе и фактически включают таблицу виртуальных методов VMT. Из функции автозаполнения кода Delphi (она зависит от информации о компиляции), мы видим, что после того, как мы введем имя объекта, а затем введем «». », Delphi перекомпилирует его, перечисляя все элементы данных и все статические методы, все виртуальные методы, все класс Методы, все конструкторы и деструкторы, вы можете попробовать это, если это так.
Адрес ввода VMT таблицы виртуальных методов класса
Информация о шаблоне членов данных
Статическая таблица методов и т. Д.
Таблица виртуальных методов VMT
Объект
Адрес записи VMT
Данные члены
Приведенная выше программа также демонстрирует выравнивание элементов данных объекта (физическая структура данных), которая выровнена в 4 байтах (выравнивание Windows по умолчанию), как показано на рисунке ниже:
VMT Entrance Addr
я
CH1CH2
Дж
2 Конструктор и создание объектов
2.1 Что такое конструктор? («Специальный» метод)
Из семантики идеи OO (объектно-ориентированной) конструктор отвечает за создание объекта, но с точки зрения реализации языка ООП, будь то Delphi или C ++, только инициализация объекта (включая объект (включая объект (включая объект (включая объект (включая объект (включая объект (включая объект (включая объект (включая объект Призыв внутренних субобъектов).
Кроме того, в отличие от C ++, Delphi определяет другой тип метода для конструктора (MkConstructor, см. Line /source/rtl/common/typinfo.pas, строка 125 в каталоге установки Delphi), который мы можем понимать как «специальный» метод класса. Полем Его можно вызвать только через класс (имя класса/ссылка на класс/указатель класса), в то время как общие методы класса могут быть вызваны как через классы, так и объекты; и в методах класса, я указывает на класс, где мы обычно инициализируем его члены данных, чтобы сделать его реальным объектом, что является всем благодаря самостоятельному параметру.
По умолчанию конструктор представляет собой статическую функцию, мы можем установить его как виртуальный метод и переопределить его в своем полученном классе. Создает несколько конструкторов и также может напрямую наложить конструктор родительского класса в производном классе. структуры и разрушения (см. 4)
2.2 Весь процесс создания объекта
Полный процесс создания объекта должен включать распределение пространства, создание структур физических данных, инициализацию и создание внутренних субъектов. Как упомянуто выше, конструктор отвечает только за инициализацию и вызов конструктора внутренних субобъектов. Это потому, что компилятор делает дополнительные вещи, мы не знаем. При составлении конструктора перед построением функции будет вставлена строка «Call @classcreate». :
функция _classcreate (Aclass: Tclass; Alloc: Boolean): Tobject;
Асм
{ -> eax = указатель на VMT}
{<- eax = указатель на экземпляр}
…
Call Dword Ptr [eax] .vmtnewinstance // Вызов NewInstance
…
End;
Vmtnewinstance = -12;
Функция класса NewInstance: Tobject;
Функция класса tobject.newinstance: tobject;
Начинать
Результат: = initInstance (_getMem (enceSicesize));
конец;
"InitInstance (_getMem (enceSicesize))" вызывает три функции по очереди:
1) Сначала вызов EnceSancesize (), чтобы вернуть размер объекта фактического класса
Функция класса tobject.instancesize: longint;
Начинать
Результат: = pinteger (Integer (self) + vmtinStancesize)^; // возвращать размер объекта фактического класса
конец;
2) Вызовите _getmem (), чтобы выделить память размером с экземпляр в куче и вернуть ссылку объекта
3) Вызовите initinstance () для построения физической структуры данных и установите значение по умолчанию элемента, например, установление значения элемента целочисленного данных на 0, установление указателя на нуль и т. Д. Если есть виртуальный метод, назначьте адрес записи таблицы виртуальных методов VMT первым четырем байтам объекта.
После вызова NewInstance, объект в это время имеет только «пустую оболочку» и отсутствие фактического «содержания», поэтому необходимо вызвать настраиваемый конструктор для инициализации объекта и вызов конструктора внутреннего суб-объекта, включить Объекты в программе действительно отражают объекты в реальном мире. Это весь процесс создания объекта.
2.3 Альтернативное использование конструкторов (используя классовые ссылки для реализации полиморфизма конструкторов)
В Delphi классы также хранятся в качестве объектов, поэтому существует также полиморфизм. Установите метод класса как виртуальный метод, переопределите его в его полученном классе, а затем вызовите его через ссылку/указатель базового класса, чтобы объект был построен на основе ссылки класса/указателя, указывающего на фактический класс. Пожалуйста, смотрите следующую программу:
Tmyclass = class
конструктор Create; Virtual;
конец;
Ttmyclass = class of tmyclass; // Справочник класса базового класса
Tmyclasssub = class (tmyclass)
конструктор создать;
конец;
Процедура CreateObj (Aclass: ttmyclass; var ref);
Начинать
Tobject (ref): = aclass.create;
// ref не имеет типа и несовместимо с любым типом, поэтому он должен быть явно отображен при использовании (отлив)
// Aclass - это ссылка на класс, единый интерфейс функции и различные реализации.
// он будет построить объекты на основе фактического ссылочного класса/указано на Aclass.
Конец;
…
CreateObj (tmyclass, obj);
CreateObj (tmyclasssub, subobj);
3 деструктор и уничтожение объектов
3.1 Что такое деструктор («естественно» виртуальный метод)
Семантически говоря, деструктор отвечает за уничтожение объектов и освобождение ресурсов. В Дельфи, синонимичный.
Delphi также определяет тип метода для деструктора (MKConstructor, см. Line /source/rtl/common/typinfo.pas, 125 в каталоге Delphi Installation). Виртуально; "во всех предках VCL Class - Tobject. Почему VCL делает это? Потому что это гарантирует, что объект может быть правильно разрушен в полиморфных ситуациях. Если виртуальные методы не используются, вы можете только разрушить базовый класс Subobject, что приведет к так называемой «утечке памяти». Следовательно, чтобы обеспечить правильный деструктор, деструктор должен добавить объявление переопределения.
3.2 Весь процесс разрушения объектов
Сначала уничтожьте полученный подборщик класса, а затем уничтожьте субобект базового класса.
намекать
В полученном классе базовый суб-объект класса относится к части, унаследованной от базового класса, а дочерний объект в полученном классе относится к недавно добавленной части.
3.3 Уничтожить, бесплатно, freeandnil, использование и различия выпуска
Уничтожить: виртуальный метод
Отпустить память, объявить его виртуальным в Tobject, обычно переопределяйте ее в подклассе и добавьте наследственное ключевое слово, чтобы гарантировать, что производный объект класса правильно уничтожен;
Но уничтожение не может быть использовано напрямую, почему?
Если объект равна нулю, мы все равно называем уничтожение, возникнет ошибка. Поскольку Destress является виртуальным методом, ему необходимо найти входной адрес таблицы виртуальных методов VMT на основе первых четырех байтов в объекте, чтобы найти входной адрес уничтожения, поэтому объект должен существовать в настоящее время. Но свободный - это статический метод. Использование свободного безопаснее, чем использование Dissult.
2) Свободный: статический метод
Проверьте, является ли объект нулевой, а уничтожение называется, если он не ноль. Вот код Delphi бесплатно:
процедура tobject.free;
Начинать
Если я <> nil, тогда
Разрушать;
конец;
Разве не здорово учиться на своих сильных и слабых сторонах?
Тем не менее, вызов Destrol просто разрушает объект, но не устанавливает ссылку объекта на NIL, который должен быть сделан программистом.
3) Freeandnil;
Определение FreeAndnil в единице Sysutils
Процедура FreeAndnil (var obj);
вар
Темп: Тобъект;
Начинать
Temp: = tobject (obj);
Указатель (OBJ): = NIL;
Temp.free;
конец;
Мы рекомендуем вам использовать его вместо свободного/уничтожения, чтобы убедиться, что объект выпускается правильно.
4) Выпуск;
Свободная функция вызывается после того, как все события в окне обрабатываются. Он часто используется для уничтожения Windows, а когда обработка событий занимает определенное количество времени в этом окне, этот метод может гарантировать, что окно разрушено только после обработки окна. Вот исходный код Delphi tcustomform.release:
Процедура tcustomform.release;
Начинать
Postmessage (Handle, CM_Release, 0, 0);
// Отправить сообщение CM_RELEASE в окно в очередь сообщения.
// вызовут процесс обработки сообщений CM_RELEASE CMRELEASE снова
конец;
Давайте посмотрим на следующее определение CMRelease для обработки сообщений CM_RELEASE:
процедура cmreLease (var Сообщение: tmessage);
Процедура tcustomform.cmrelease;
Начинать
Бесплатно;
конец;
4 VCL Construction & Destructuring Architecture Architecture
Тобжет
Конструктор Create; // Статический метод
разрушитель уничтожает;
ТЕРСИСИСКИЙ
разрушитель разрушает;
TComponent
конструктор Create (AOHOWNER: TCOMPONT);
разрушитель разрушает;
Tcontrol
конструктор Create (AOHOWNER: TCOMPONT);
разрушитель разрушает;
…
В следующем анализе исходный код строительства и разрушения в VCL, принимая TControl в качестве примера:
конструктор tcontrol.create (aowner: tcomponent);
Начинать
Унаследованные Create (AOHOWNER); // Создать субобект базового класса и передать права на деструктуризацию AOHOWNER. Положить это впереди
// это обеспечивает порядок «сначала создания базового класса, а затем создание субобъектов полученного класса»
… // инициализируйте и вызовите конструктор внутреннего субобекта
конец;
Destructor tcontrol.destroy;
Начинать
… // разрушают внутренние субобъекты в полученных классах
унаследован Destroy; // разрушить объект базового класса и положить его в конце
// Это обеспечивает порядок «первого разрушения полученных субобъектов класса, а затем разрушение субобъектов базового класса»
конец;
5 Правильно используйте конструкторы и деструкторы
После приведенного выше анализа в следующем приведении принципы использования конструкторов и деструкторов:
Перед использованием объекта вы должны сначала создать объект и вовремя уничтожить объект, чтобы освободить ресурсы.
Когда два объекта относятся к назначениям, убедитесь, что безымянный объект (ссылаясь на объекты, на которые не упоминаются), которые появляются, может быть опубликован.
При создании компонента рекомендуется настроить компонент хоста (то есть использовать параметр Aowner, обычно форму), и Aowner управляет разрушением объектов, поэтому нет необходимости беспокоиться об уничтожении компонента Delphi на разработке формы/модуля данных и создание компонентов - это метод. Поэтому нам не нужно писать деструктор, который называет компонент.
Когда тип возврата функции является объектом, результат также является ссылкой на объект, гарантируя, что должен существовать объект, на который необходимо существовать результат.
Чтобы использовать obj <> nil или назначить (nil), чтобы проверить, что объект существует, obj: = nil также следует вызвать после obj: = nil.
Пожалуйста, обратитесь к исходному коду демо -программы
Инструкции (рекомендуется)
Все программы Delphi были переданы на Win2K+Delphi6 SP2. Чтобы углубить ваше понимание этой статьи, рекомендуется обратиться к демонстрационной программе.
Эта статья включает в себя некоторые из моих опытов и опыта в обучении VCL/RTL.
Прежде чем читать эту статью, читатели должны иметь определенное понимание ориентированного языка Паскаля и иметь возможность понимать полиморфизм.
Благодаря этой статье вы должны быть в состоянии понять объектную модель, механизм построения и разрушения в Delphi, а также архитектуру строительства и разрушения в VCL и иметь возможность освоить использование методов строительства и разрушения. Структура и разрушение в Delphi намного проще, чем в C ++, и мы должны быть в состоянии освоить ее.