Области видимости
При описании нового класса важен разумный компромисс. С одной стороны, требуется скрыть от других методы и поля, представляющие собой внутреннее устройство класса (для этого и придуманы свойства). Маловажные детали на уровне пользователя объекта будут бесполезны и только помешают целостности восприятия.
С другой стороны, если слишком ограничить того, кто будет порождать классы-потомки, и не обеспечить ему достаточный набор инструментальных средств и свободу маневра, то он и не станет использовать ваш класс.
В модели объектов языка Object Pascal существует механизм доступа к составным частям объекта, определяющий области, где ими можно пользоваться (области видимости). Поля и методы могут относиться к четырем группам (секциям), отличающимся областями видимости. Методы и свойства могут быть общими (секция public), личными (секция private), защищенными (секция protected) и опубликованными (секция published). Есть еще и пятая группа, automated, она ранее использовалась для создания объектов СОМ; теперь она присутствует в языке только для обратной совместимости с программами на Delphi версий 3—5.
Области видимости, определяемые первыми тремя директивами, таковы.
Рассмотрим пример, иллюстрирующий три варианта областей видимости.
Листинг 1.1. Пример задания областей видимости методов
unit First; | unit Second;
interface | interface
| uses First;
type | type
TFirstObj = class | TSecondObj =class(TFirstObj}
private | procedure Method4;
procedure Methodl; | end;
protected |
procedure Method2; |
public |
procedure Methods; |
end; |
procedure TestProcl; | procedure TestProc2;
implementation | implementation
uses dialogs; | varAFirstObj :TFirstObj;
var AFirstObj: TFirstObj;|ASecondObj: TSecondObj;
procedure TestProcl; | procedure TSecondObj.Method4;
begin | begin
AFirstCbj := TFirstObj.Create; | Methodl; {недопустимо -
AFirstObj.Methodl;(допустимо)|
|произойдет ошибка компиляции}
AFirstObj.Method2; {допустимо}| Method2; {допустимо}
AFirstObj.MethodS; {допустимо}| Methods,- {допустимо}
AFirstObj.Free; | end;
end;
| procedure TestProc2;
procedure TFirstObj.Methodl; | begin
begin |AFirstObj:=TFirstObj.Create;
ShowMessage('1'); |AFirstObj.Methodl;{недопустимо}
end; |AFirstObj.Method2;{недопустимо}
procedure TFirstObj.Method2;
|AFirstObj.Method3;{допустимо}
begin |AFirstObj.Free;
ShowMessage('2');
Methodl; |ASecondCbj:= TSecondObj.Create;
end; |ASecondObj.Methodl;{недопустимо}
procedureTFirstObj.Method3;
|ASecondObj.Method2;{допустимо}
begin |ASecondObj.MethodS;{допустимо}
ShowMessage('3'); |ASecondObj.Free;
Method2; | end;
end; |end.
end. |
Если к этому примеру добавить модуль Third и попробовать вызвать методы классов TFirstObj и TSecondObj оттуда, то к числу недоступных будет отнесен и Method2 — он доступен только в том модуле, в котором описан.
Наконец, область видимости, определяемая четвертой директивой — published, имеет особое значение для интерфейса визуального проектирования Delphi. В этой секции должны быть собраны те свойства объекта, которые будут видны не только во время исполнения приложения, но и из среды разработки. Публиковать можно свойства большинства типов, за исключением старого типа real (теперь он называется rеаl48), свойств типа "массив" и некоторых других. Все свойства компонентов, доступные через
Инспектор объектов, являются их опубликованными свойствами. Во время выполнения такие свойства общедоступны, как и public.
Три области видимости — private, protected, public — как бы упорядочены по возрастанию видимости методов. В классах-потомках можно повысить видимость методов и свойств, но не понизить ее. При описании дочернего класса можно переносить методы и свойства из одной сферы видимости в другую, не переписывая их заново и даже не описывая — достаточно упомянуть о нем в другом месте:
type
TFirstObj = class
private
FNumber: Integer;
protected
property Number: Integer read: FNumber;
end;
...
TSecondObj = class(TFirstObj)
published
property Number;
end;
Если какое-либо свойство объекта из состава VCL принадлежит к области public, вернуть его в private невозможно. Напротив, обратная процедура широко практикуется в Delphi. У многих компонентов (например, TEdit) есть предок (в данном случае TCustomEdit), который отличается только отсутствием опубликованных свойств. Так что, если вы хотите создать новый редактирующий компонент, порождайте его на базе TCustomEdit и публикуйте только те свойства, которые считаете нужными. Разумеется, если вы поместили свойство в область private, "достать" его оттуда в потомках возможности уже нет.