Шаг 138.
Область видимости в классах

    На этом шаге мы перечислим правлила, определяющие область видимости в классах и рассмотрим применяющиеся при этом конструкции.

    Область видимости идентификаторов, объявленных в классах, в общем случае распространяется:

    Дополнительно область видимости идентификаторов в классах может ограничиваться правилами области видимости в блоках, а также специальными директивами управления областью видимости published, public,protected, private и automated. Директивы public и private уже знакомы тем, кто программировал на Borland Pascal.


    Директивы published, protected и automated являются нововведением Object Pascal. Причем директива automated появилась только в 32-разрядной версии Delphi.

    Рассмотрим действие директив видимости.

Директива public

    Поля, свойства и методы, описанные в разделе public, называются общедоступными или публичными. Их область видимости подчиняется рассмотренным правилам общего случая. Поля, свойства и методы, расположенные сразу после заголовка класса, при выключенной директиве компилятора {$М-}, по умолчанию принимаются общедоступными.

Директива published

    Поля, свойства и методы, описанные в разделе published, называются опубликованными. Их область видимости эквивалентна области видимости общедоступных описаний. Отличие состоит в том, что для опубликованных полей, свойств и методов генерируется дополнительная информация об их типе, которая доступна во время выполнения. Благодаря этой информации при создании и помещении компонент на палитру, их опубликованные свойства становятся доступными в Object Inspector. Однако такие свойства могут быть только ограниченного числа типов. А именно, порядковых типов, вещественных типов, за исключением Real, типа String, типа "множество" с максимальным числом элементов не более 15, а также классового типа и типа "указатель на метод". Описания, расположенные сразу после заголовка класса, при включенной директиве компилятора {$М+}, по умолчанию принимаются опубликованными.

Директива automated

    Поля, свойства и методы, описанные в разделе automated, назовем по имени директивы автоматическими. Их область видимости эквивалентна области видимости общедоступных описаний. Отличие состоит в том, что для автоматических свойств и методов генерируется дополнительная информация, которая используется для реализации OLE-механизма. Использовать директиву automated имеет смысл при объявлени потомков стандартного класса TAutoObject.

Директива private

    Поля, свойства и методы, описанные в разделе private, называются приватными или личными. Их область видимости ограничивается пределами того модуля, в котором они описаны и где они доступны так же, как и public-описания. Раздел private в рамках объявления класса играет роль, аналогичную роли раздела реализации модуля implementation. To есть скрытие информации разработчика, о которой не должен знать пользователь, включающий созданный модуль в предложении uses.

Директива protected

    Поля, свойства и методы, описанные в разделе 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. Результат работы приложения

    Со следующего шага мы начнем рассматривать статические, виртуальные и динамические методы.




Предыдущий шаг Содержание Следующий шаг