Delphi 3. Библиотека программиста

       

Использование inheritedс переопределенными свойствами


Предположим, вы разрабатываете VCL-компонент Delphi (например, потомок TDrawGrid)и хотите предпринять некоторые особые действия в тот момент, когда пользователь (в нашем случае — программист) изменяет свойство ColCount. Это можно сделать двумя способами; выбор зависит от того, хотите вы получить простое уведомление об изменении или вам необходимо ограничить набор возможных значений ColCount.

Свойство ColCount определяет количество столбцов в сетке. Его значение, как и значение большинства свойств, хранится в private-поле (в нашем случае — FColCount) и изменяется private-методом (SetColCount). Следовательно, когда в программе встречается строка

ColCount := AValue;

или значение ColCount изменяется в инспекторе объектов в режиме конструи рования, вызывается метод SetColCount, который с помощью других private-методов изменяет значение переменной FColCount и вносит необходимые изменения в сетку. Все это инкапсулировано и недоступно для вмешательства извне.

Однако разработчики исходной версии TDrawGrid предусмотрели, что при создании компонентов-потомков может потребоваться уведомление об изменении количества столбцов — поэтому после внесения изменений, но перед их отображением, вызывается метод SizeChanged. Метод SizeChanged является динамическим, то есть его можно переопределить, и после этого при каждом изменении количества столбцов (или строк) будет вызываться новая версия SizeChanged. См. листинг 9.9.

Листинг 9.9. SIZECHAN.SRC

{ Потомок TDrawGrid с переопределенным методом SizeChanged. Это позволяет компоненту-потомку узнавать об изменении количества столбцов или строк. } { В секции interface... } type TMyGrid = class(TDrawGrid) protected procedure SizeChanged(OldColCount, OldRowCount: Longint); override; end; { В секции implementation... } procedure TMyGrid.SizeChanged(OldColCount, OldRowCount: Longint); begin { Выполняем любые необходимые действия } end;

Переопределение SizeChanged позволит получать необходимые уведомления, но плохо подходит для контроля за количеством столбцов (скажем, если число столбцов в нашей сетке не должно превышать 3). К моменту вызова SizeChanged (обратите внимание на прошедшее время — Changed — в названии метода) изменения уже внесены. Лучшее, что мы можем сделать, если свойство ColCount стало равно 4, — заменить его на 3 и повторить весь процесс.

Чтобы как можно раньше узнавать об изменениях, мы можем переопределить само свойство ColCount, задав для него новые методы доступа (см. объявление TMyGrid в листинге 9.10). Такое переопределение скрывает свойство ColCount предка. Если теперь в программе встретится строка:

ColCount := AValue;

будет вызван наш, невиртуальный метод SetColCount. Как видно из текста метода (см. листинг 9.10), мы сначала проверяем, не превышает ли новое количество столбцов 3, и если не превышает — вносим изменения.

Листинг 9.10. SETCOLCT.SRC

{ Потомок TDrawGrid, переопределяющий свойство ColCount

с новыми методами доступа. Это позволяет компоненту-потомку

управлять количеством столбцов. }

{ В секции interface... }

type TMyGrid = class(TDrawGrid) private function GetColCount: LongInt; procedure SetColCount(Value: LongInt); published property ColCount: LongInt read GetColCount write SetColCount default 0; end; { В секции implementation... } function TMyGrid.GetColCount: LongInt; begin Result := inherited ColCount; end; procedure TMyGrid.SetColCount(Value: LongInt); begin if Value <= 3 then inherited ColCount := Value; end;

Но, вероятно, самое интересное в переопределяемых свойствах — способ их изменения. Мы не можем непосредственно модифицировать значение private-поля FColCount. Впрочем, прямая модификация привела бы к нежелательным эффектам из-за пропуска ряда необходимых действий, сопровожда ющих изменение числа столбцов. Мы не можем вызвать метод SetColCount предка, потому что он определен в разделе private. А попытка вставить в наш метод SelColCount строку вида

ColCount := Value;

приведет к бесконечной рекурсии и переполнению стека.

Правильный ответ заключается в использовании ключевого слова inherited с именем свойства:

inherited ColCount := Value;

Возможность использования inherited с именем свойства предка не так хорошо документирована, как его применение к унаследованным public- и protected-методам. Для кого-то такая возможность станет приятной неожиданностью, но она вполне в духе Object Pascal.



Содержание раздела