- •Объектно-ориентированное программирование
- •Часть 1 классы и объекты
- •Введение
- •1. Классы и объекты
- •Var aLine: tLine;
- •Var aColorLine: tColorLine;
- •2. Методы
- •2.1. Методы-функции и методы-процедуры
- •2.2. Конструкторы и деструкторы
- •Inherited Create;
- •Var TmpFrm: tForm;
- •Var Mem: tMemo;
- •2.3. Классовые процедуры и функции
- •Var s: String;
- •2.4. Скрытый Self
- •3. Видимость компонентов класса
- •4. Наследование
- •4.1. Основные понятия
- •4.2. Наследование полей
- •4.3. Поведение методов при наследовании
- •Var SomeObject: t1;
- •Virtual;
- •Virtual; Abstract;
- •4.4. Иерархия классов
- •4.5. Rtti
- •4.6. Проверка типа
- •4.7. Приведение типа
- •4.8. Указатели на класс
- •Var ObjRef: tObjRef;
- •Implementation
- •X, y, w, h: Integer): tControl;
- •5. Полиморфизм
- •6. Свойства (properties)
- •6.1. Объявление свойств
- •6.2. Объявления свойств-массивов
- •Var I: Byte;
- •6.3. Раздел Read
- •6.4. Раздел Write
- •Inherited Create;
- •Inherited Destroy;
- •6.5. Команды Default, NoDefault и Stored
- •6.6. Команда Index
- •Var aYear, aMonth, aDay: Word;
- •Var aYear, aMonth, aDay: Word;
- •6.7. Команды DispId и Implements
- •6.8. Переопределение свойств при наследовании
- •7. События (events)
- •7.1. Объявление событий
- •IfAssigned(fOnMouseMove) Then fOnMouseMove(Self, Shift, X, y);
- •Vk_return: NumMemo.DoNumStr(l);
- •Vk_return: PostMessage(NumMemo.Handle, wm_user1,1, 0);
- •7.2. Обработчики событий
- •7.3. Делегирование событий
- •Var Objl: tIstClass;
- •7.4. Переопределение стандартных событий
- •Var NewBtn: tNewButton;
Var s: String;
Begin
S:=TCoIorLine.Cla»sParent.ClassNanie; // S содержит TLine S:=ALine.ClassName; // S содержит TLine
Наибольшие возможности заложены в функции Classlnfo, для обслуживания которой в Delphi предусмотрен целый блок Typlnfo, включающий большой набор методов, позволяющих манипулировать информацией о типах объектов, типах свойств объектов, типах указателей на методы, присваивать значения свойствам объектов. Следует только иметь в виду, что подробная информация для RTTI генерируется для раздела Published потомков класса TPersistent. Примеры использования этой функции имеются в источниках, приведенных в списке литературы.
б) Реализация классовых методов.
Реализация классового метода достаточно проста. Основное отличие заключается в том, что реализация должна начинаться с зарезервированного слова Class.
Синтаксис реализации классовых методов следующий:
Class Procedure <имя класса>.<имя процедуры>[(<параметры>)];
[<блок объявлений>]
Begin
<Исполняемые операторы>
End;
Class Function <имя класса>.<имя функции>[(<параметры>)]:
<тип результатам, [<блок обьявлений>]
Begin
<Исполняемые операторы>
Result:'=<возвращаемое значение>;
<Исполняемые операторы>
End;
Примечания:
• Как всегда в теле функции должен быть хотя бы один оператор, присваивающий идентификатору функции либо предопределенной переменной Result возвращаемое значение.
• Важно помнить, что внутри классового метода нет доступа к полям экземпляра класса.
в) Вызов классовых методов. Классовые методы могут быть вызваны несколькими способами:
• с использованием имени класса:
<имя класса>.<имя классового метода>[{<параметры>}];
• через экземпляр класса, т.е. как обычный метод, а именно:
<имя объекта>.<имя классового метода>[(<параметры>)];
• классовые методы могут также вызываться с помощью переменной' типа указателя на класс.
2.4. Скрытый Self
Между самостоятельными подпрограммами и методами, исключая классовые, имеется существенное отличие, которое состоит в способе доступа к данным экземпляра класса.
Как известно, для того, чтобы самостоятельные подпрограммы могли работать с элементами данных, эти данные должны быть переданы подпрограммам, предпочтительно в виде параметров. Кроме того, самостоятельные подпрограммы имеют доступ к любым данным, объявленным глобально в модуле или программе, а также ко всем глобальным переменным других модулей, перечисленных в списке секции Uses.
Методы, исключая классовые, имеют, помимо этого, неявный доступ к полям того экземпляра класса, который был использован при их вызове. Это происходит потому, что фактически при вызове в каждый метод передается дополнительный параметр - указатель на использовавшийся при вызове метода объект, а внутри метода стоит неявный оператор With, заключающий в себе все тело метода. Этот неявный параметр (предопределенный идентификатор) называется Self, и он имеет тот же тип. что и класс, в котором определен метод.
Все тело метода заключено в неявный оператор With Self Do, который предоставляет методу доступ к полям, свойствам и другим методам данного объекта. Поскольку параметр Self неявно присутствует внутри метода, то в большинстве случаев не будет возникать необходимости в его явном использовании. Его явное использование может понадобиться, например, для разрешения конфликтов идентификаторов внутри метода, когда имя локальной переменной совпадает с именем поля. Тогда для обращения к полю, например, FTitle следует указать Self.FTitle.
Параметр Self часто используется, когда требуется обратиться к текущей форме в одном из ее методов. Типичный пример - динамическое создание компонента, когда нужно передать параметр Owner (т.е. указать владельца) конструктору Create. Например, по щелчку мыши по форме (событие OnMouseDown) или даже по щелчку по другой кнопке (событие OnClick) можно создать кнопку.
With TButton.Create(Sell) Do Begin
Parent:=Self; // Указывать Fonnl не требуется
SetBounds(X,Y,W,H); // (X- Left, Y- Top. W- Width, H - Height)
Name:='NewButton'; // Caption также будет равно NewButton
Visible:=True;
. . . // Значения других свойств
End;
Поскольку классовые методы могут вызываться и при отсутствии экземпляров класса, то они не могут иметь доступ к полям класса, поэтому у них отсутствует встроенный Self, и нет возможности использовать его поля, поэтому для классовых методов Self - переменная типа ссылки на класс, чей классовый метод был вызван. Фактически Self для классовых методов указывает на VMT.