В процессе использования DELPHI для разработки программного обеспечения мы подобны группе счастливых коров и овец на лугу, беззаботно наслаждающихся солнечным светом, который дарит нам язык Object Pascal, и богатыми водными растениями, обеспечиваемыми различными элементами управления VCL. Глядя на безграничное голубое небо, глядя вниз на пышную зеленую траву на земле, кто бы мог подумать о том, насколько велика Вселенная и какие вещи меньше молекул и атомов? Это дело философов. В это время философ сидел на вершине высокой горы, смотрел вверх на изменения в туманностях Вселенной, смотрел на ползающих по земле насекомых, внезапно оглядываясь назад, кивая и улыбаясь нашей группе пасущихся крупный рогатый скот и овцы. Он взял травинку, осторожно подержал ее во рту, закрыл глаза и внимательно попробовал ее на вкус. Интересно, какой вкус был у этой травки во рту философа? Однако на его лице всегда была довольная улыбка.
Знание и понимание микроскопического атомарного мира DELPHI может позволить нам полностью понять макроскопическую структуру приложений DELPHI, тем самым развивая наше программное обеспечение в более широком идеологическом пространстве. Это похоже на то, как будто Ньютон открыл движение макроскопических объектов, но был обеспокоен тем, что не мог понять, почему объекты движутся именно так. Напротив, Эйнштейн пережил счастливую жизнь относительности между законами основных частиц и движением макроскопических объектов. !
Раздел 1. Атом объекта TObject.
Что такое ТОбъект?
Это базовое ядро архитектуры языка Object Pascal и источник различных элементов управления VCL. Мы можем думать о TObject как об одном из атомов, составляющих приложение DELPHI. Конечно, они состоят из более тонких частиц, таких как базовые элементы синтаксиса Паскаля.
Говорят, что TObject является атомом программы DELPHI, поскольку TObject поддерживается внутри компилятора DELPHI. Все классы объектов являются производными от TObject, даже если вы не указываете TObject в качестве класса-предка. TObject определяется в модуле System, который является частью системы. В начале модуля System.pas есть текст комментария:
{Предопределенные константы, типы, процедуры, }
{ и функции (например, True, Integer или }
{Writeln) не имеют фактических деклараций.}
{ Вместо этого они встроены в компилятор }
{ и рассматриваются так, как если бы они были объявлены }
{ в начале системного блока.}
Это означает, что этот модуль содержит предопределенные константы, типы, процедуры и функции (например: True, Integer или Writeln). Они фактически не объявлены, но встроены компилятором и используются в начале компиляции. быть установленным определением. Вы можете добавить другие файлы исходной программы, такие как Classes.pas или Windows.pas, в файл проекта для компиляции и отладки исходного кода, но вы абсолютно не можете добавить файл исходной программы System.pas в файл проекта для компиляции! DELPHI сообщит об ошибках компиляции для повторяющихся определений System!
Таким образом, TObject — это определение, предоставляемое компилятором внутри. Для тех из нас, кто использует DELPHI для разработки программ, TObject — это атомарная вещь.
Определение TObject в модуле System следующее:
ТОбъект = класс
конструктор Создать;
процедура Бесплатно;
функция класса InitInstance (Экземпляр: Указатель): TObject;
процедура CleanupInstance;
функция ClassType: TClass;
функция класса ClassName: ShortString;
функция класса ClassNameIs (const Name: string): Boolean;
функция класса ClassParent: TClass;
функция класса ClassInfo: Указатель;
функция класса InstanceSize: Longint;
функция класса InheritsFrom(AClass: TClass): Boolean;
функция класса MethodAddress(const Name: ShortString): Указатель;
функция класса MethodName (Адрес: Указатель): ShortString;
функция FieldAddress(const Name: ShortString): Указатель;
функция GetInterface(const IID: TGUID; out Obj): Boolean;
функция класса GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
функция класса GetInterfaceTable: PInterfaceTable;
функция SafeCallException (ExceptObject: TObject;
ExceptAddr: Указатель): HResult virtual;
процедура AfterConstruction виртуальная;
процедура BeforeDestruction виртуальная;
процедура Dispatch (вар Сообщение виртуальное);
процедура DefaultHandler (вар Сообщение виртуальное);
функция класса NewInstance: TObject виртуальный;
процедура FreeInstance виртуальная;
деструктор Уничтожить виртуальный;
конец;
Далее мы будем постепенно постучаться в дверь атомов TObject, чтобы посмотреть, какая структура находится внутри.
Мы знаем, что TObject — это базовый класс всех объектов. Так что же такое объект?
Любой объект в DELPHI — это указатель, который указывает место, занимаемое объектом в памяти! Хотя объект является указателем, когда мы ссылаемся на члены объекта, нам не нужно писать код MyObject^.GetName, а можно только написать MyObject.GetName. Это расширенный синтаксис языка Object Pascal. поддерживается компилятором. Друзья, использующие C++ Builder, очень четко понимают взаимосвязь между объектами и указателями, поскольку объекты в C++ Builder должны определяться как указатели. Место, на которое указывает указатель объекта, — это пространство объекта, в котором объект хранит данные. Давайте проанализируем структуру данных пространства памяти, на которое указывает указатель объекта.
Первые 4 байта пространства объектов указывают на таблицу адресов виртуальных методов (таблица виртуальных методов VMT?C) класса объектов. Следующее пространство — это пространство для хранения данных-членов самого объекта, оно хранится в общем порядке от элементов данных самого примитивного класса-предка объекта до членов данных объектного класса, а также в том порядке, в котором члены данных определяются на каждом уровне класса.
Таблица виртуальных методов класса (VMT) содержит адреса процедур виртуальных методов всех классов, производных от исходного класса-предка. Виртуальный метод класса — это метод, объявленный с зарезервированным словом virtual. Виртуальный метод — это базовый механизм достижения полиморфизма объектов. Хотя динамические методы, объявленные с зарезервированным словом Dynamic, также могут обеспечивать полиморфизм объектов, такие методы не хранятся в таблице адресов виртуальных методов (VMT). Это всего лишь еще один метод, предоставляемый Object Pascal, который может сэкономить пространство для хранения классов. Механизм полиморфной реализации. но в ущерб скорости звонка.
Даже если мы сами не определяем какой-либо виртуальный метод класса, объект класса все равно имеет указатель на таблицу адресов виртуального метода, но длина записи адреса равна нулю. Однако где хранятся виртуальные методы, определенные в TObject, такие как Destroy, FreeInstance и т. д.? Оказывается, адреса их методов хранятся в пространстве со смещением в отрицательном направлении относительно указателя VMT. Фактически, смещение пространства данных на 76 байт в отрицательном направлении таблицы VMT представляет собой системную структуру данных класса объектов. Эти структуры данных связаны с компилятором и могут быть изменены в будущих версиях DELPHI.
Следовательно, можно думать, что VMT — это структура данных, начинающаяся с адресного пространства с отрицательным смещением. Область данных с отрицательным смещением — это область системных данных VMT, а данные с положительным смещением VMT — это область пользовательских данных (настраиваемый виртуальный метод). адресная таблица). Функции и процедуры, связанные с информацией о классе или информацией о времени выполнения объекта, определенной в TObject, обычно связаны с системными данными VMT.
Данные VMT представляют собой класс. Фактически, VMT — это класс! В Object Pascal мы используем такие идентификаторы, как TObject, TComponent и т. д., для представления классов, которые реализуются как соответствующие им данные VMT внутри DELPHI. Тип класса, определенный с помощью класса зарезервированного слова, на самом деле является указателем на соответствующие данные VMT.
Для нашего приложения данные VMT являются статическими данными. После того, как компилятор скомпилировал наше приложение, эта информация данных была определена и инициализирована. Программные операторы, которые мы пишем, могут получать доступ к информации, связанной с VMT, получать такую информацию, как размер объекта, имя класса или данные атрибутов времени выполнения, или вызывать виртуальные методы, или читать имя и адрес метода и т. д.
Когда объект создается, система выделяет для него пространство памяти и связывает его с соответствующим классом. Таким образом, первые 4 байта в пространстве данных, выделенном для объекта, становятся указателями на данные класса VMT.
Давайте посмотрим, как объекты рождаются и умирают. Наблюдая за тем, как мой трехлетний сын прыгает по траве, именно потому, что я стал свидетелем процесса рождения жизни, я могу по-настоящему понять смысл и величие жизни. Только те, кто пережил смерть, поймут и будут больше ценить жизнь. Итак, давайте разберемся в процессе создания и уничтожения объектов!
Мы все знаем, что простейший объект можно построить с помощью следующего утверждения:
AnObject := TObject.Create;
Компилятор реализует свою компиляцию как:
На основе VMT, соответствующего TObject, вызовите конструктор Create TObject. Конструктор Create вызывает системный процесс ClassCreate, а системный процесс ClassCreate вызывает виртуальный метод NewInstance через хранящийся в нем класс VMT. Цель вызова метода NewInstance — установить пространство экземпляра объекта. Поскольку мы не перегрузили этот метод, это NewInstance класса TObject. Метод NewInstance класса TObjec вызовет процедуру GetMem для выделения памяти для объекта на основе размера экземпляра объекта (InstanceSize), инициализированного компилятором в таблице VMT, а затем вызовет метод InitInstance для инициализации выделенного пространства. Метод InitInstance сначала инициализирует первые 4 байта пространства объектов как указатель на VMT, соответствующий классу объектов, а затем очищает оставшееся пространство. После создания экземпляра объекта также вызывается виртуальный метод AfterConstruction. Наконец, сохраните указатель адреса данных экземпляра объекта в переменной AnObject, и таким образом появится объект AnObject.
Аналогично, объект можно уничтожить, используя следующий оператор:
АнОбъект.Уничтожить;
Деструктор TObject, Destroy, объявлен как виртуальный метод, который также является одним из встроенных виртуальных методов системы. Метод Destory сначала вызывает виртуальный метод BeforeDestruction, а затем вызывает системный процесс ClassDestroy. Процесс ClassDestory вызывает виртуальный метод FreeInstance через класс VMT, а метод FreeInstance вызывает процесс FreeMem для освобождения пространства памяти объекта. Вот так объект исчезает из системы.
Процесс разрушения объектов проще, чем процесс создания объектов, точно так же, как зарождение жизни — это длительный процесс вынашивания, но смерть относительно недолговечна. Это кажется неизбежным правилом.
В процессе создания и уничтожения объекта вызываются две виртуальные функции, NewInstance и FreeInstance, для создания и освобождения пространства памяти экземпляра объекта. Причина, по которой эти две функции объявлены как виртуальные, заключается в том, чтобы предоставить пользователям возможность расширения при написании специальных классов объектов, которые требуют от пользователей управления собственной памятью (например, в некоторых специальных программах промышленного управления).
Объявление AfterConstruction и BeforeDestruction как виртуальных функций также должно дать производному классу в будущем возможность позволить новорожденному объекту вдохнуть первый глоток свежего воздуха после создания объекта и позволить объекту завершить последствия до того, как объект умрет. . Это все имеет смысл. Фактически, событие OnCreate и событие OnDestroy объекта TForm и объекта TDataModule запускаются соответственно в двух процессах виртуальных функций: перегрузке TForm и TDataModule.
Кроме того, TObjec также предоставляет метод Free, который не является виртуальным методом. Он специально предназначен для безопасного освобождения объекта, когда неясно, является ли объект пустым (ноль). Фактически, если вы не можете выяснить, пуст ли объект, возникает проблема неясной логики программы. Однако никто не идеален и может совершать ошибки. Использование Free также полезно, чтобы избежать случайных ошибок. Однако написание правильных программ не может полагаться исключительно на такие решения. Первой целью программирования должно быть обеспечение логической корректности программы!
Заинтересованные друзья могут прочитать оригинальный код модуля System, где большой объем кода написан на языке ассемблера. Внимательные друзья могут обнаружить, что конструктор Create и деструктор Destory TObject не написали никакого кода. Фактически, через окно Debug CPU в состоянии отладки можно четко отобразить ассемблерный код Create и Destory. Потому что мастера, создавшие DELPHI, не хотели предоставлять пользователям слишком много сложных вещей. Они хотели, чтобы пользователи писали приложения, основанные на простых концепциях, и скрывали для них сложную работу внутри системы. Поэтому при публикации модуля System.pas коды этих двух функций специально удаляются, чтобы заставить пользователей думать, что TObject — это источник всего сущего, а пользовательские классы и вовсе начинаются с небытия. Это само по себе не является неправильным. Хотя чтение этих наиболее важных кодов DELPHI требует небольшого знания языка ассемблера, чтение таких кодов может дать нам более глубокое понимание происхождения и развития мира DELPHI. Даже если вы мало что понимаете, способность понимать хотя бы некоторые базовые вещи окажет нам большую помощь при написании программ DELPHI.
Раздел 2. TClass Atom
В модуле System.pas TClass определяется следующим образом:
TClass = класс TObject;
Это означает, что TClass — это класс TObject. Поскольку TObject сам по себе является классом, TClass — это так называемый класс классов.
Концептуально TClass — это тип класса, то есть класс. Однако мы знаем, что класс DELPHI представляет собой часть данных VMT. Таким образом, класс можно рассматривать как тип, определенный для элемента данных VMT. Фактически, это тип указателя, указывающий на данные VMT!
В предыдущем традиционном языке C++ тип класса не мог быть определен. После компиляции объекта он фиксируется, структурная информация класса преобразуется в абсолютный машинный код, и полная информация о классе не будет существовать в памяти. Некоторые объектно-ориентированные языки более высокого уровня могут поддерживать динамический доступ и вызов информации о классе, но они часто требуют сложного внутреннего механизма интерпретации и большего количества системных ресурсов. Язык Object Pascal DELPHI вобрал в себя некоторые замечательные особенности объектно-ориентированных языков высокого уровня, сохраняя при этом традиционное преимущество прямой компиляции программ в машинный код, что прекрасно решает проблемы расширенных функций и эффективности программ.
Именно потому, что DELPHI сохраняет в приложении полную информацию о классах, он может предоставлять расширенные объектно-ориентированные функции, такие как преобразование и идентификация классов во время выполнения, в которых ключевую роль играют данные VMT класса. Заинтересованные друзья могут прочитать два процесса сборки AsClass и IsClass в модуле System. Это коды реализации операторов as и is, позволяющие глубже понять классы и данные VMT.
...
Следующий контент также включает понимание вымышленных конструкторов, механизма реализации интерфейса, механизма реализации обработки исключений и т. д. Основные принципы DLPHI. Я надеюсь, что смогу закончить его после Первомая и поделиться им со всеми.