На этом шаге мы перечислим правлила, определяющие область видимости в классах и рассмотрим применяющиеся при этом конструкции.
Область видимости идентификаторов, объявленных в классах, в общем случае распространяется:
Дополнительно область видимости идентификаторов в классах может ограничиваться правилами области видимости в блоках, а также специальными директивами управления областью видимости published, public,protected, private и automated. Директивы public и private уже знакомы тем, кто программировал на Borland Pascal.
Рассмотрим действие директив видимости.
Поля, свойства и методы, описанные в разделе public, называются общедоступными или публичными. Их область видимости подчиняется рассмотренным правилам общего случая. Поля, свойства и методы, расположенные сразу после заголовка класса, при выключенной директиве компилятора {$М-}, по умолчанию принимаются общедоступными.
Поля, свойства и методы, описанные в разделе published, называются опубликованными. Их область видимости эквивалентна области видимости общедоступных описаний. Отличие состоит в том, что для опубликованных полей, свойств и методов генерируется дополнительная информация об их типе, которая доступна во время выполнения. Благодаря этой информации при создании и помещении компонент на палитру, их опубликованные свойства становятся доступными в Object Inspector. Однако такие свойства могут быть только ограниченного числа типов. А именно, порядковых типов, вещественных типов, за исключением Real, типа String, типа "множество" с максимальным числом элементов не более 15, а также классового типа и типа "указатель на метод". Описания, расположенные сразу после заголовка класса, при включенной директиве компилятора {$М+}, по умолчанию принимаются опубликованными.
Поля, свойства и методы, описанные в разделе automated, назовем по имени директивы автоматическими. Их область видимости эквивалентна области видимости общедоступных описаний. Отличие состоит в том, что для автоматических свойств и методов генерируется дополнительная информация, которая используется для реализации OLE-механизма. Использовать директиву automated имеет смысл при объявлени потомков стандартного класса TAutoObject.
Поля, свойства и методы, описанные в разделе private, называются приватными или личными. Их область видимости ограничивается пределами того модуля, в котором они описаны и где они доступны так же, как и public-описания. Раздел private в рамках объявления класса играет роль, аналогичную роли раздела реализации модуля implementation. To есть скрытие информации разработчика, о которой не должен знать пользователь, включающий созданный модуль в предложении uses.
Поля, свойства и методы, описанные в разделе protected, называются защищенными. В отличие от двух других новых директив published и automated, которые в смысле области видимости являются модификациями public, директива protected определяет принципиально отличные правила области видимости и обеспечивает ограничение доступа наряду с директивой private. Но если private обеспечивает защиту на уровне исходного модуля, где сделаны описания, то protected ограничивает доступ на уровне исходного класса, где были объявлены поля свойства и методы. Причем механизм защиты у protected не такой "прямолинейный", как у private (только "свой" модуль и ничего более). Protected защищает свои описания от прямого использования объектами в других модулях. То есть, если protected-описания принадлежат, например, классу TBaseClass в модуле Unit1, то объекты класса TBaseClass, объявленные в "своем" модуле, могут работать с ними, а объекты того же класса, объявленные в других модулях, импортирующих модуль Unit1, не могут. Но если в импортирующих модулях использование защищенных описаний "прямыми " объектами класса TBaseClass запрещено, то на использование таких объявлений потомками класса TBaseClass никаких ограничений не накладывается ни в "своем" модуле, ни в модулях, которые его используют.
Покажем применение директивы protected на примере.
unit Unit1; { Модуль, в котором объявляется класс TBaseClass, } { имеющий защищенные описания } interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Memo1: TMemo; Label1: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; TBaseClass = class protected FField : Integer; FProperty : Integer; function GetField : Integer; procedure SetField ( Value : Integer ); function GetProperty : Integer; procedure SetProperty ( Value : Integer ); property PProperty : Integer read GetProperty write SetProperty; end; var Form1: TForm1; BaseVar: TBaseClass; implementation {$R *.dfm} function TBaseClass.GetField : Integer; begin Result := FField end; procedure TBaseClass.SetField ( Value : Integer ); begin FField := Value end; function TBaseClass.GetProperty : Integer; begin Result := FProperty end; procedure TBaseClass.SetProperty ( Value : Integer ); begin FProperty := Value end; procedure TForm1.FormCreate(Sender: TObject); var Tmp : Integer; S : String; begin BaseVar := TBaseClass.Create; { В "своем" модуле защищенные поля, методы и свойства } { доступны также, как и public, и private-описания } with BaseVar do begin FField := 1; SetField(2); Tmp := GetField; Str (Tmp, S); S := 'BaseVar.FField = ' + S; Form1.Memo1.Lines.Add( S ); PProperty := 3; Tmp := PProperty; Str (Tmp, S); S := 'BaseVar.PProperty = ' + S; Form1.Memo1.Lines.Add ( S ); end; BaseVar.Free; end; end.
Результат:
Рис.1. Результат работы приложения
unit Unit1; { Модуль, в котором объявляется класс TBaseClass, } { имеющий защищенные описания } interface type TBaseClass = class protected FField : Integer; FProperty : Integer; function GetField : Integer; procedure SetField ( Value : Integer ); function GetProperty : Integer; procedure SetProperty ( Value : Integer ); property PProperty : Integer read GetProperty write SetProperty; end; var BaseVar: TBaseClass; implementation function TBaseClass.GetField : Integer; begin Result := FField end; procedure TBaseClass.SetField ( Value : Integer ); begin FField := Value end; function TBaseClass.GetProperty : Integer; begin Result := FProperty end; procedure TBaseClass.SetProperty ( Value : Integer ); begin FProperty := Value end; end.
unit Un_New; { Модуль, который импортирует класс TBaseClass, } { имеющий защищенные описания } interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Unit1; type TForm1 = class(TForm) Memo1: TMemo; Label1: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; TMyClass = class (TBaseClass) end; var Form1: TForm1; BaseVar: TBaseClass; MyVar : TMyClass; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var Tmp : Integer; S : String; begin { Защищенные поля, методы и свойства объектов класса } { TBaseClass, описанного в подключаемом модуле UProtecl, } { в данном модуле UProtec2 не доступны. } // BaseVar := TBaseClass.Create; // with BaseVar do // begin // FField := 1; Поле недоступно // SetField(2); Метод недоступен // Tmp := GetField; Метод недоступен // Str (Tmp, S); // S := 'BaseVar.FField = ' + S; // Form1.Memo1.Lines.Add( S ); // PProperty := 3; Свойство недоступно // Tmp := PProperty; Свойство недоступно // Str (Tmp, S); // S := 'BaseVar.PProperty = ' + S; // Form1.Memo1.Lines.Add ( S ); // end; { Защищенные поля, методы и свойства объектов класса } { TMyClass, являющегося потомком класса TBaseClass, } { который описан в подключаемом модуле UProtecl, } { в данном модуле UProtec2 доступны } MyVar := TMyClass.Create; with MyVar do begin FField := 1; SetField(2); Tmp := GetField; Str (Tmp, S); S := 'MyVar.FField = ' + S; Form1.Memo1.Lines.Add( S ); PProperty := 3; Tmp := PProperty; Str (Tmp, S); S := 'MyVar.PProperty = ' + S; Form1.Memo1.Lines.Add( S ); end; MyVar.Free; end; end.
Результат:
Рис.2. Результат работы приложения
Со следующего шага мы начнем рассматривать статические, виртуальные и динамические методы.