- •Объектно-ориентированное программирование
- •Часть 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;
6.2. Объявления свойств-массивов
Объявление свойств-массивов имеет ряд особенностей как при их объявлении, так и при использовании.
Синтаксис объявления свойства-массива класса:
Property <имя cвoucmвa>[[Const] <индекс1>:<тип шдекса>
[; [Coast] <индекс2>:<тип индекса>] ]: <тип данных>
[Read <метод чтения>]
[Write <метод записи>][; Default];
Примечания:
• Индексы свойств-массивов оформляются аналогично параметрам процедур и функции, но только в квадратных скобках.
• Идентификатор индекса свойства-массива может дополняться спецификатором Const.
• Команда Default отделяется от других команд объявления свойства-массива точкой с запятой и должна быть последней.
• Свойства-массивы могут иметь индексы любого стандартного типа.
• Property FieldValues[Const FieldName: String]: Variant; Default;
// Свойство строкового типа компонентов Table, Query u TSoredProc, используемых для работы с базами данных. Есть строковый индекс и у TStrings. Values.
• Function GetValue(Const Name: String): String;
Procedure SetValue(Const Name, Value: String);
Property Values[Const Name: String]; String Read GetValue Write SetValue;
• Type
ArrStr=Array[1..7] Of String[10]; // Объявление типа - массива строк
TAnyClass=Class // Объявление нового класса
Private
FArr: ArrStr; // Поле-массив Function GetIntArr(iIndex: Integer): String; //Метод чтения Function GetStrArr(sIndex: String): Integer; //Метод чтения Public
Property Plnt[ilndex: Integer]: String Read GetIntArr;
Property PStr[sIndex: String]: Integer Read GetStrArr;
End;
Доступ к полю типа массив с помощью свойства со строковым индексом производится по значению строки. Фактически ищется индекс элемента массива, значение которого равно строковому индексу свойства-массива.
Function TAnyCIass.GetStrArr(sIndex: String): Integer;
Var I: Byte;
Begin
Result:=-l;
For I:=l To 7 Do IfUpperCase(FArr[I])=UpperCase(sIndex) Then Result:=I;
End;
6.3. Раздел Read
Этот раздел в объявлении свойства указывает, как получать значения свойства. Может быть указано поле (прямой доступ) или метод чтения (косвенный доступ). В последнем случае, метод чтения должен быть функцией, тип которой совпадает с типом свойства.
Примечания:
• Для простых свойств метод чтения должен быть функцией, возвращающей значение свойства.
• Для векторных свойств, метод чтения должен быть функцией, имеющей один индексный параметр и возвращающей значение свойства.
• Для свойств-массивов метод чтения должен быть функцией с таким же количеством и типом параметров, что и индексы в объявлении свойства-массива, и это функция должна возвращать значение свойства.
• Метод должен быть объявлен в определении класса до ссылки на него в объявлении свойства или в видимых разделах классов-предков. Рекомендуемое соглашение об именовании таких методов - начинать их со слова Get.
6.4. Раздел Write
Этот раздел в объявлении свойства указывает, как присваивать свойству новое значение. Может быть указано поле (прямой доступ) или метод записи (косвенный доступ). В последнем случае, метод записи должен быть процедурой с параметром, тип которого совпадает с типом свойства.
Примечания:
• Для простых свойств - это единственный параметр метода записи.
• Для векторных свойств, первым параметром метода записи должен быть индекс, а вторым - новые данные свойства.
• Для свойств-массивов метод записи должен иметь на единицу больше параметров, чем размерность массива. Причем последний параметр - новые данные элементов массива, а остальные - тех же типов и в той же последовательности, что и индексы массива.
• В любом случае параметр с данными должен передаваться либо по значению, либо как Const.
• Код реализации метода записи может включать процедуру Update, обновляющую представление компонента.
• Метод записи должен быть объявлен в определении класса до ссылки на него в объявлении свойства или в видимых разделах классов-предков. Рекомендуемое соглашение об именовании таких методов - начинать их со слова Set.
• Если свойство типа массив использует прямой доступ к полю, то необходимо присваивать полю весь массив одновременно (обычно с помощью вспомогательной переменной-массива).
Некоторую особенность должен иметь раздел Write для объектных свойств:
• Класс-обладатель свойства должен обязательно включать конструктор и деструктор для выделения и освобождения памяти под корреспондирующее свойству поле того же объектного типа.
• Метод Write должен производить проверку на Nil ссылки объекта, который предполагается присвоить с помощью свойства в поле объектного типа класса-обладателя свойства, например с помощью функции Assigned:
If Assigned( Value) Then FSomeObject.Assign(Value).
• Фактически следует не присваивать экземпляр класса свойству объектного типа, а копировать значения его полей, иначе будет некорректная работа с экземпляром при переприсвоении значений свойству объектного типа.
Свойства-объекты должны быть потомками класса TPersistent, если необходимо, чтобы их публикуемые свойства отображались в Инспекторе объектов Delphi. В общем случае они могут быть потомками класса Tobject.
Рассмотрим упрощенный пример объявления и использования свойства-объекта, класс которого не является потомком класса TPersistent, поэтому не будет отображаться в инспекторе объектов. Последовательность создания свойства объекта следующая:
• Объявляем класс, который будет определять тип свойства-объекта:
TAnyClass=Class Private
FFId: String; // Поле класса
Public
Procedure Assign(0bj: TObject);
Property Fid: String Read FFId Write FFId; // Свойство класса
End;
• Объявляем класс, который будет включать свойство-объект:
TPropClass=Class Private
FProp: TAnyClass; // Поле свойства-объекта
Procedure SetPropObj(Obj: TAnyClass);
Public
Constructor Create;
Destructor Destroy; Override;
Property Prop: TAnyClass Read FProp Write SetPropObj; // Свойство
End;
• Создаем реализации всех методов, объявленных в обоих классах:
Procedure TAnyClass.Assign(Obj: TObject);
Begin
IfObj Ь TAnyClass Then Fld:=TAnyClass(Obj).Fld;
End;
Constructor TPropClass.Create;
Begin
