Function TForml.GetClicks: Integer; begin

Result := FnClicks; end;

При детальном рассмотрении этого метода следует обратить внимание на два обстоятельства. Первое, метод класса имеет доступ к защищенному полю класса FnClicks. Второе обстоятельство менее очевидно и связано с рассматриваемой темой. При описании метода нельзя указать явно, поле какрго именно объекта используется для получения данных, например нельзя написать:

Result := Forml.FnClicks;

Понятно, что так нельзя сделать, поскольку метод является единым для всех объектов класса, а поля данных у всех объектов свои. Например, если будет описан другой объект класса TForml, например Form2, то необходимо, чтобы указанная строка имела вид:

Result := Fonn2 . FnClicks;

Решение вопроса как раз связано с параметром, который передается в любой метод, имеет идентификатор self, и, по сути, является ссылкой на тот объект класса, для которого вызван метод. Фактически, компилятор представляет текст метода следующим образом: function TForml.GetClicks: Integer; begin

Result := Self.FnClicks; end;

Если метод был вызван как Forml. GetClicks, то вместо self будет подставлен адрес объекта Forml. Таким образом, через параметр self вычисляются реальные адреса полей во время выполнения программы. (В С++ и Java для тех же целей используется ключевое слово this).

Пример. В Delphi ключевое слово Self часто используется, когда нужно явно обратиться к текущей форме в одном из ее методов. Типичный пример - динамическое создание компонента, когда в конструктор компонента Create необходимо передать параметр Owner (указать владельца), а затем присвоить то же значение свойству Parent (указать родителя). Тем и другим для создаваемого компонента является текущая форма, и лучшим способом указать на нее является использование self.

Пример 3.5. Обработчик события нажатия клавиши мыши на форме, который создает объект типа кнопка в том месте, где была нажата клавиша мыши

i>rocedure TForml. FormMouseDovm (Sender: TObject; Button:

TMousaButton; Shift: TShiftState; X, Y: Integer);

Var

Btn : TButton; begin

Btn := TButton.Create (self) Btn.Parent :» self; Btn.Left := X; Btn.Top := Y; Btn.Width := Btn.Width + 50; »tn.Caption := Format {'Кнопка на %d %d', [X, Y]) ; •rid;

Данный код создает кнопки там, где происходит щелчок мыши. Если вместо •elf передавать переменную Forml, то если в приложении появится несколько жземпляров формы ~ возникнет ошибка. Вообще, использование конкретного представителя класса в тех случаях, когда надо явно обратиться к текущему объекту, является плохим стилем программирования.

Конструкторы и деструкторы

Конструкторы - это специальные методы, создающие и инициализирующие объекты. Объявление конструктора выглядит как объявление метода, но предваряется ключевым словом constructor. В качестве имени конструктора обычно используют Create.

Type

TMyButton = class constructor Create;

And; var

Btn : TMyButton;

Если конструктор применяется к классу, то сначала происходит создание объекта - под него отводится память, значения всех полей «обнуляются», при тгом порядковым типам в качестве начального значения задается значение с номером 0, указателям присваивается nil, строки задаются пустыми, а поля типа Variant получают значение Unassigned. Затем выполняется код конструктора, в котором обычно описывается инициализация элементов объектов класса (присваивание полям и свойствам начальных значений и пр.) и иозвращается указатель на созданный экземпляр объекта. Например:

Btn := TMyButton.Create;

Конструктор может применяться и к объекту, например: Itn.Create;

В этом случае новый экземпляр объекта не создается, а выполняется только .ип'оритм конструктора. Фактически происходит переинициализация объекта. При и ом нельзя применять конструктор к еще неинициализированной переменной, поскольку память под нее еще не была распределена.

В реализации конструктора вначале обычно идет вызов конструктора класса предка с помощью ключевого слова inherited. В результате инициализируются все наследуемые поля. Затем в новом конструкторе инициализируются поля, введенные в данном классе.

Деструкторы - это специальные методы, уничтожающие объект и освобождающие место в оперативной памяти. Объявление деструктора выглядит также как объявление процедуры, но предваряется ключевым словом destructor. В качестве имени деструктора обычно задаютDestroy.

Реализация деструктора, как правило, завершается вызовом наследуемого деструктора с помощью ключевого словаinherited, чтобы освободить память от наследуемых полей.

Вместо того чтобы вызывать деструкторDestroy напрямую, принято вызывать специальную процедуруFree, действие которой состоит в том, что она вызывает деструкторDestroy только в том случае, если объект существует (то есть ссылка на него не равна nil). Следует учитывать, что методFree не устанавливает все ссылки на объект равными nil автоматически; если это необходимо, это должен делать сам программист, поскольку объект «не знает», какие переменные на него ссылаются.

При "рассмотрении конструкторов и деструкторов необходимо учитывать, что их нельзя использовать для компонентов Delphi (для объектов любых классов, произошедших от классаTComponent). Любой компонент, попавший при визуальном проектировании из Палитры компонентов в приложение, определяет своим владельцем форму (контейнер), на которую он помещен и для него конструкторы и деструкторы вызываются автоматически, при создании (уничтожении) владельца, то есть формы. Создание и уничтожение форм делает приложение (глобальный объект с именем Application), для этого в файле проекта вызывается методApplication. CreateForm.

§3.6. Наследование классов

Если необходимо создать новый класс, лишь немного отличающийся от уже существующего, то нет необходимости в переписывании заново уже существующих полей и методов. В этом случае можно объявить, что новый класс TNewCLass = class (TOldClass)

является потомком или дочерним классом существующего класса, называемого предком или родительским классом. Все классы Object Pascal имеют единого общего родителя - классTObject. Этот класс не имеет полей и свойств, но включает в себя методы самого общего назначения, обеспечивающие весь жизненный цикл любых объектов - от их создания до уничтожения.

Новый класс наследует методы, поля, свойства своего родителя. В новом классе обычно добавляются новые методы, поля и свойства. В случае если новое поле или свойство имеет идентификатор, совпадающий с идентификатором поля или свойства в родительском классе, то соответствующий элемент родительского

класса становится недоступным (перекрывается). Удалять объявленные в родительском классе поля, свойства и методы нельзя. 11ример 3.6. Наследование классов, type

TParentClass = class I: integer;

CounterValue: integer; end;

TChildClasa » class (TParentC:lass) CounterValue: longint; J: integer; end; var

Parent : TParentClass; Child : TChildClass;

В рассматриваемом примере объзктchild будет иметь три поля:

· X типа Integer - унаследованное из класса TParentClass;

· CounterValue типа Longing _ новое поле, которое перекрыло поле CounterValue типа Integer водительского класса;

· J типа Integer - новое поле, огределенное в классе TChildClass.

Для методов при наследовании действуют те же правила, что и для полей классов, за исключением совпаденю идентификаторов методов в классе-родителе иклассе-потомке. В этих случая: для методов определены более сложные механизмы переопределения (nepe:pbvrae, перегрузка и др.). Выбор того или иного механизма определяется видод метода, который задается при его описании специальными директивами. К пер^му ВИДу относятся статические методы, ко иторому - виртуальные (virtual) и динамические (dynamic) и, наконец, к фетьему - перегружаемые (overl<a<j) методы.

Модель наследования в Delphi hi поддерживает множественное наследование. ')то значит, что каждый класс може- иметь только один базовый класс. Частично реализовать множественное наслед^ание можно с использованием интерфейсов.

§3.7.Статические методы

Если при описании метода не задавались дополнительные директивы (по умолчанию), то метод является статическим. Если в классе-наследнике переопределить такой метод, то ДОИобъектов этого класса новый метод отменит родительский. Если обращаться кмехоДу этого класса, то вызываться будет новый метод. Но если обратиться к^ъекту, как к объекту родительского класса, го вызываться будет метод родителя

11ример 3.7. Пусть задан класс точе:TPoint и класс окружностей -TCircle,который является наследником tiacca точек. В обоих классах определен статический метод с именемDraw.

Interface

Type

TPoint = class X, 1 Integer;

constructor Create (a, b: integer); procedure Draw (Newx, Newy : integer); end;

TCircle = class (TPoint) Radius : Integer;

Наши рекомендации