Конструкторы и деструкторы
Составляющие класса 1. Поля. Полями называются инкапсулированные в классе данные. Поля могут быть любого типа, в том числе классами. Type TMyClass=class aIntField:integer; aStrField:String; aObjectField:TObject; end; Каждый объект получает уникальный набор полей но общий для всех объектов данного класса набор методов и свойств. В Object Pascal разрешается обращаться к полям напрямую: Var aObject:TMyClass; begin aObject.aIntField:=0; aObject.aStrField:=’Строка символов’; end; Класс-потомок получает все поля всех своих предков и может дополнять их своими, но он не может переопределить их или удалить. Таком образом, чем ниже в дереве иерархии располагается класс, тем больше данных получают в свое распоряжение его объекты.
Объектами называют отдельные экземпляры классов. Чтобы перейти от описания классов к объектам, следует выполнить объявление в секции var. Type TDiskGauge=class … End; Var DiskGauge:TdiskGauge;
2. Методы. Инкапсулированные в классе процедуры и функции называются методами. Они объявляются также, как и обычные подпрограммы: Type TMyClass=class Function MyFunc(aPar:Integer):Integer; Procedure MyProc; End; Доступ к методам класса, как и к его полям, возможен с помощью составных имен: Var AObject:TMyClass; Begin AObject.MyProc; End; Методы класса могут перекрываться в потомках. Type TparentClass=class Procedure DoWork; End; TchildClass=class(TparentClass) Procedure DoWork; End; Потомки обоих классов могут выполнять сходную по названию процедуру DoWork, но, в общем случае, будут делать это по-разному. Такое замещение методов называется статическим, т.к. реализуется компилятором. В Object Pascal гораздо чаще используется динамическое замещение методов на этапе прогонки программы. Для реализации этого метод, замещаемый в родительском классе, должен объявляться как динамический (с директовой dynamic) или виртуальный (virtual). Встретив такое объявление, компилятор создаст две таблицы – DMT (Dynamic Method Table) и VMT (Virtual Method Table) и поместит в них адреса точек входа соответственно динамических и виртуальных методов. При каждом обращении к замещаемому методу компилятор вставляет код, позволяющий извлечь адрес точки входа в подпрограмму из той или иной таблицы. В классе-потомке замещающий метод объявляется с директивой override (перекрыть). Получив это указание, компилятор создаст код, который на этапе прогона программы поместит в родительскую таблицу точку входа метода класса-потомка, что позволит родителю выполнить нужное действие с помощью нового метода.
Разница между динамическими и виртуальными методами состоит в том, что таблица динамических методов DMT содержит адреса только тех методов, которые объявлены как dynamic в данном классе, в то время как таблица VMT содержит адреса всех виртуальных методов не только данного класса, но и всех его родителей. Значительно большая по размеру таблица VMT обеспечивает более быстрый поиск, в то время как при обращении к динамическому методу программа сначала просматривает таблицу DMT у объекта, затем – у его родительского класса и так далее, пока не будет найдена нужная точка входа. Динамически перекрываемые методы часто могут вообще ничего не делать. Такие методы называются абстрактными, они обязаны перекрываться в потомках. Программист может запретить вызов абстрактного метода, объявив его с директивой abstract. В грамотно составленной программе абстрактные методы никогда не вызываются. Классы, содержащие абстрактные методы, называются абстрактными. Такие классы инкапсулируют общие свойства своих неабстрактных потомков, но объекты абстрактных классов никогда не создаются и не используются. Для эксплуатации абстрактных классов в библиотеку классов Delphi включаются классы-потомки, в которых перекрываются абстрактные методы родителя.
Конструкторы и деструкторы В состав любого класса входят два специальных метода – конструктор и деструктор. У класса Tobject эти методы называются Create и Destroy, так же они называются и в подавляющем большинстве потомков. Конструктор распределяет объект в динамической памяти и помещает адрес этой памяти в переменную Self, которая автоматически объявляется в классе. Деструктор удаляет объект из кучи. Обращение к деструктору должно предварять любое обращение к полям и некоторым методам объекта. По своей форме конструкторы и деструкторы являются процедурами, но объявляются с помощью зарезервированных слов Constructor и Destructor: Type TMyClass=class IntField:Integer; Constructor Create(Value:Integer); Destructor Destroy; End; Любые поля объекта, а также методы класса, оперирующие с его полями, могут вызываться только после создания объекта с помощью вызова конструктора, т.к. конструкторы распределяют объект в динамической памяти и делают действительным содержащийся в объекте указатель. Var MyObject:MyClass; Begin MyObject:=TmyClass.Create; … MyObject.Free; End; В базовом классе TObject определен метод Free, который сначала проверяет действительность адреса объекта и лишь затем вызывает деструктор Destroy. Большинство конструкторов реализуют некоторые действия, необходимые для правильной работы объекта. Поэтому в конструкторе класса-потомка следует сначала вызвать конструктор своего родителя, а уже затем осуществлять дополнительные действия. Вызов любого метода родительского класса достигается с помощью зарезервированного слова Inherited (унаследованный): Constructor TmyClass.Create(Value:Integer); Begin Inherited Create; // вызываем унаследованный конструтор … End; Некоторые методы могут вызываться без создания и инициации объекта. Такие методы называются методами класса, они объявляются с помощью зарезервированного слова class: Type TMyClass=class Class Function GetClassName:String; End; Var S:String; Begin S:=TMyClass.GetClassName; … End; Методы класса не должны обращаться к полям, т.к. в общем случае вызываются без создания объекта, а следовательно, в момент вызова полей просто не существует. Обычно они возвращают служебную информацию о классе – имя класса, имя его родительского класса, адрес метода и т.п.
Конструктор применяется к классу и к объекту. Если конструктор применяется к классу, DiskGauge:=TdiskGauge.Create; то выполняется следующая последовательность действий: · в динамической памяти выделяется место для нового объекта; · выделенная память заполняется нулями; · выполняются заданные программистом действия конструктора; · ссылка на созданные объект возвращается в качестве значения конструктора; тип возвращаемого значения совпадает с типом класса, использованного при вызове. Если конструктор применяется к объекту DiskGause.Create; то новый объект не создается, а происходит переинициализация полей существующего. В этом случае конструктор не возвращает никакого значения. Деструктор уничтожает объект, к которому применяется, в результате: · выполняется заданный программистом код деинициализации, · освобождается занимаемая объектом динамическая память.
Одноименные методы В Delphi 4,5 появилась возможность в рамках одного класса иметь несколько одноименных методов. Механизм перекрытия родительского метода одноименным методом потомка приводит к тому, что потомок «не видит» перекрытый родительский метод и может обращаться к нему лишь с помощью зарезервированного слова Inherited. В Delphi 4 введено зарезервированное слово overload (перезагрузить), с помощью которого становятся видны одноименные методы как родителя, так и потомка. Чтобы одноименные методы можно было отличить друг от друга, каждый из них должен иметь уникальный набор параметров. При обнаружении одноименного метода компилятор предупреждает о том, что у класса уже есть аналогичный метод с другими параметрами. Для подавления сообщений объявление одноименного метода можно сопровождать зарезервированным словом reintroduce (вновь ввести). Пример: В классе Tform1 используется 4 одноименных метода Close. Лишь один из них – унаследованный метод без параметра выполняет свои основные функции – закрывает окно. Три других отличаются набором параметров и выводят сообщения в заголовок окна. Procedure TForm1.Button1Click(Senter:TObject);
Begin Close(‘Строка символов’); End; Procedure TForm1.Button2Click(Senter:TObject); Begin Close(123); End; Procedure TForm1.Button3Click(Senter:TObject); Begin Close(20,300); End; Procedure TForm1.Button4Click(Senter:TObject); Begin Close; End; В разделе private класса Tform1 вставить 3 объявления методов Close Private Procedure Close(S:string); reintroduce; overload; Procedure Close(I:integer); reintroduce; overload; Procedure Close(I,J:integer); reintroduce; overload; Implementation Procedure Tform1.Close(S:String); Begin Caption:=S; End; Procedure Tform1.Close(I:Integer); Begin Caption:=IntToStr(I); End; Procedure Tform1.Close(I,J:Integer); Begin Caption:=IntToStr(I*J); End; 3. Свойства. Свойства – это специальный механизм классов, регулирующий доступ к полям. Свойства объявляются с помощью зарезервированных слов property, read и write (слова read и write считаются зарезервированными только в контексте объявления свойства). Обычно свойство связано с некоторым полем и указывает те методы класса, которые должны использоваться при записи в это поле или при чтении из него. Type TClass=class IntField:integer; Function GetField:Integer; Procedure setField(value:Integer); Property IntegerValue:Integer read GetField write SetField;
В контексте программы свойство ведет себя как обычное поле. Var aClass:TClass; value:Integer; begin aClass:=TClass.Create; {Обязательно! Перед обращением к полю или свойству!} aClass.IntegerValue:=0; Value:=aClass.IntegerValue; End; Разница между оператором aClass.IntField:=NewValue; и оператором aClass.IntegerValue:=NewValue; заключается в том, что при обращении к свойству автоматически подключается метод SetField, в котором могут реализовываться специальные действия. Если необходимо, чтобы поле было доступно только для чтения или только для записи, следует опустить часть write или read. Вообще говоря, свойство сожжет и не связываться с полем. Фактически оно описывает один или два метода, которые осуществляют некоторые действия над данными того же типа, что и свойство.
ОБЪЯВЛЕНИЕ КЛАССА
Любой вновь создаваемый класс может содержать секции (разделы), определяемые зарезервированными словами · published (декларированные), · private (личные), · protected (защищенные), · public (доступные), · automated (автоматизированные). Внутри каждой секции вначале определяются поля, а затем – методы и свойства. Секции определяют область видимости элементов описания класса. Секция public не накладывает ограничений на область видимости перечисляемых в ней полей, методов и свойств – их можно вызывать в любом другом модуле программы. Секция published также не ограничивает область видимости, однако в ней перечисляются свойства, которые должны быть доступны не только на этапе исполнения, но и на этапе конструирования объектов. Секция published используется только при разработке нестандартных компонентов. Среда Delphi помещает описания компонентов, вставленных в форму, в специальную секцию без названия, которая располагается сразу за заголовком класса и продолжается до первой объявленной секции. Это секция published. Программисту не следует помещать в нее собственные элементы описания класса или удалять из нее элементы, вставленные средой. Секция private сужает область видимости до минимума: личные элементы описания доступны только внутри методов данного класса и в подпрограммах, находящихся в том же модуле, где описан класс. Элемент, объявленный в секции private, становится недоступным даже ближайшим потомкам класса, если они размещаются в других модулях. Секция protected доступна только методам самого класса, а также любым его потомкам независимо от того, находятся ли они в том же модуле или нет. Секция automated используется только для объявления свойств и методов, которые будут добавлены к так называемому интерфейсу OLE-объектов автоматизации; область видимости членов этой секции не ограничена.
В Object Pascal разрешается сколько угодно раз объявлять любую секцию, причем порядок следования секций не имеет значения. Любая секция может быть пустой. При объявлении класса-потомка разрешается перемещать элементы класса из одной области видимости в другую. После перемещения в секцию private элемент объявления становится невидимым потомкам (если потомок, как это обычно бывает, объявляется в другом модуле) и, следовательно, его уже нельзя переместить в другую секцию. Класс может объявляться только в интерфейсной области модуля или в самом начале области реализации. Нельзя объявлять классы в разделе описания подпрограмм.
Воспользуйтесь поиском по сайту: ©2015 - 2025 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|