На первый взгляд свойство компонента
На первый взгляд свойство компонента не отличается от обычного элемента данных класса (поля). Действительно, в приведенном выше листинге мы видим выражения вроде
Cal->Month =12;
Cal->Year++;
Свойству можно присваивать значение, извлекать из него значение и вообще вроде бы делать с ним все то, что делают с простым полем. Действительно, свойство, как правило, имеет ассоциированное с ним поле, и иногда операции над свойством не означают ничего, кроме соответствующих операций над его полем. Но в примере из предыдущего раздела вы могли видеть, как простое присваивание значения, например, свойству Month календаря сразу меняет все его содержимое. Другими словами, свойство может иметь непосредственный коррелят в “реальном мире” компьютерного экрана. Механизм свойств обеспечивает компонентам ту их реальность, о которой мы говорили чуть выше.
Все это означает, что изменение значения свойства должно сопровождаться некоторыми побочными действиями, и потому присваивание значения свойству реализуется посредством вызова некоторой функции. Такие функции называют обычно set-функциями, а функции для чтения свойств — get-функциями. И те и другие называются функциями доступа.
Наш пример с календарем позволит нам исследовать некоторые аспекты свойств. Откройте окно обозревателя классов, если оно еще не открыто (View Explorer в контекстном меню редактора). Найдите в нем узел TCCalendar и дважды щелкните на нем кнопкой мыши. В редакторе откроется файл ccalendr.h, и курсор будет установлен на начало определения класса календаря. В разделе published вы можете видеть несколько типичных объявлений свойств, например:
_property TDayOfWeek StartOfWeek =(read=FStartOfHeek, write=SetStartOfWeek, defauit=l);
В разделе private объявлено ассоциированное поле:
TDayOfWeek FStartOfWeek;
TDayOfWeek — это просто short. В фигурных скобках записан список атрибутов свойства, который означает, что:
Set-функция, как и поле свойства, объявлена в разделе private:
void _fastcall SetStartOfWeek(TDayOfWeek Value);
Объявление свойства Month несколько сложнее:
property Integer Month = {read=GetDateElement,
write=SetDateElement,
stored=false,
index=2,
nodefault};
Атрибуты stored и nodefault относятся к так называемым спецификаторам хранения. Атрибут index показывает, что функции доступа должны вызываться с дополнительным (первым) аргументом, равным 2. Вот объявление set-функции:
void _fastcall SetDateElement(int Index, int Value);
На самом деле календарь сохраняет дату в единственном поле FDate типа TDateTime. Свойства Year, Month, Day не имеют собственных полей, а их функции доступа (они одни и те же, только с разными индексами) оперируют полем FDate.
Исходный модуль с кодом календаря ccalendr.cpp вы можете найти в папке ...\CBuilder5\Examples\Controls\Source.