Современные технологии программирования |
Конспект лекций |
Лекция 13. Уровни доступа
Содержание
Области видимости (уровни доступа) *
Источники дополнительных сведений *
Изучаемые вопросы:
уровни доступа private, public, protected, published.
Переопределение свойств.
Области видимости (уровни доступа)
Пользователи класса могут использовать класс по-разному. Одни будут пользоваться только объектами класса. Другие будут создавать на основе используемого класса свои классы. Организация областей видимости класса позволяет разделить пользователей класса на группы, которые имеют разные возможности использования класса.
При описании нового класса важен разумный компромисс. С одной стороны, требуется скрыть от других методы и поля, представляющие собой внутреннее устройство класса (для этого и придуманы свойства). Маловажные детали на уровне пользователя будут бесполезны и только помешают целостности восприятия.
С другой стороны, если слишком ограничить разработчика, который будет порождать классы-потомки, и не обеспечить ему достаточный набор инструментальных средств и свободу действий, то он не станет использовать ваш класс.
В модели Object Pascal существует механизм управления доступом к составляющим частям объекта, определяющий области видимости, где ими можно пользоваться. Поля, методы и свойства могут относиться к пяти разделам (секциям), отличающимся областями видимости. Они могут быть:
Области видимости, определяемые первыми тремя директивами таковы:
Пример. Области видимости.
program PAccess;
{$APPTYPE CONSOLE}
uses
SysUtils,
Mod1 in 'Mod1.pas',
Mod2 in 'Mod2.pas',
Mod3 in 'Mod3.pas',
var
a: TMyClass1;
begin
a:= TMyClass1.Create;
// a.Field; //неверно: свойство находится вне области видимости
// Mod2.a.Field;//неверно: свойство находится вне области видимости
// Mod2.b.Field;//неверно: свойство находится вне области видимости
writeln(Mod3.a.Field);
readln;
end.
//-------------------------------------------------------------------------
unit Mod1;
interface
Type
TMyClass1 = class
private
FField: Real;
protected
property Field: Real read FField write FField;
procedure M;
end;
var a: TMyClass1;
implementation
procedure TMyClass1.M;
begin
end;
//Свойство с уровнем protected доступно в подпрограммах модуля, где
//описан класс
procedure Print(a: TMyClass1);
begin
writeln('Mod1, a: ',a.ClassName,' FField = ',a.Field);
end;
initialization
a:= TMyClass1.Create;
a.FField:= 1; //Поле с уровнем private доступно в модуле, где описан класс
writeln(a.Field);
Print(a); //Свойство с уровнем protected доступно в модуле, где
//описан класс
finalization
a.Free;
end.
//-------------------------------------------------------------------------
unit Mod2;
interface
uses Mod1;
Type
TMyClass2 = class(TMyClass1)
end;
var
a: TMyClass1;
b: TMyClass2;
implementation
procedure Print(a: TMyClass2);
begin
writeln('Mod1, a: ',a.ClassName,' FField = ',a.Field);
end;
initialization
//-------------------------------------------------------------------
b:= TMyClass2.Create;
//b.FField := 3; неверно: поле находится вне области видимости
b.Field:= 2;
Print(b);
//-------------------------------------------------------------------
a:= TMyClass1.Create;
//a.FField:= 5; неверно: поле находится вне области видимости
//a.Field =: 3; неверно: свойство находится вне области видимости
finalization
a.Free;
b.Free;
end.
//-------------------------------------------------------------------
unit Mod3;
interface
uses Mod2;
Type
TMyClass3 = class(TMyClass2)
public
property Field;
end;
var
a: TMyClass3;
implementation
procedure Print(a: TMyClass3);
begin
writeln('Mod1, a: ',a.ClassName,' FField = ',a.Field);
end;
initialization
a:= TMyClass3.Create;
a.Field:= 3;
Print(a);
finalization
a.Free;
end.
Область видимости, определяемая директивой published, имеет особое значение для интерфейса визуального проектирования Delphi. В этой секции могут быть собраны те свойства объекта, которые будут видны не только во время выполнения приложения, но и из среды разработки. Публиковать можно свойства большинства типов, за исключением типа real, свойства типа массив и некоторых других. Все свойства компонентов, доступные через Инспектор объектов, являются их опубликованными свойствами. Во время выполнения такие свойства общедоступны, как и public.
Три области видимости – private, protected, public -- как бы упорядочены по возрастанию видимости элементов класса. В классах потомках можно повысить видимость свойств, но не понизить её. При описании дочернего класса можно переносить свойства из одной сферы видимости в другую, не переписывая их заново и даже не описывая, -- достаточно упомянуть о нём в другом месте.
type
TFClass = class
private
FNumber: Integer;
protected
property Number: Integer read FNumber;
end;
TSClass = class(TFClass)
published
property Number;
end;
Если какое-либо свойство объекта из состава VCL принадлежит к области private, вернуть его в public невозможно. У многих компонентов (например, TEdit) есть предок (в данном случае TCustomEdit), который отличается только отсутствием опубликованных свойств. Так что, если вы хотите создать новый редактирующий компонент, порождайте его на базе TCustomEdit и публикуйте только те свойства, которые считаете нужными. Разумеется, если вы поместили свойство в область private, “достать” его оттуда в потомках возможности уже нет.
Пример использования раздела с уровнем доступа protected.
unit ULength;
interface
uses SysUtils;
const d = 2.54;
type
TLength = class
private
FLen: real;//длина в сантиметрах
protected
function GetSmStr:string;
procedure PutSmStr(newA:string);
function GetDmStr:string;
procedure PutDmStr(newA:string);
function GetDm:real;
procedure PutDm(newA:real);
public
property SmStr:string read GetSmStr write PutSmStr;
property DmStr:string read GetDmStr write PutDmStr;
property Dm: real read GetDm write PutDm;
property Sm: real read FLen write FLen;
constructor create(l: real = 0);
end;
var
L : TLength;
implementation
constructor TLength.Create(l: real);
begin
Sm:= l;
end;
function TLength.GetDmStr:string;
begin
GetDmStr:= FloatToStr(FLen*d);
end;
procedure TLength.PutDmStr(newA:string);
begin
FLen:= StrToFloat(newa)/d
end;
function TLength.GetSmStr:string;
begin
GetSmStr:= FloatToStr(FLen);
end;
procedure TLength.PutSmStr(newA:string);
begin
FLen:= StrToFloat(newa)
end;
function TLength.GetDm:real;
begin
GetDm:= FLen/d;
end;
procedure TLength.PutDm(newA:real);
begin
FLen:= newa*d
end;
initialization
finalization
end.
unit UCircle;
interface
uses ULength;
type
TCircle = class(TLength)
property Radius: Real read GetDm write PutDm;
function SquareSm: Real;
function PerimetrSm: Real;
function SquareDm: Real;
function PerimetrDm: Real;
end;
var Circle: TCircle;
implementation
function TCircle.SquareSm;
begin
result:= pi * System.Sqr(Sm);
end;
function TCircle.SquareDm;
begin
result:= pi * System.Sqr(Dm);
end;
function TCircle.PerimetrSm;
begin
result:= 2 * pi * Sm;
end;
function TCircle.PerimetrDm;
begin
result:= 2 * pi * Dm;
end;
end.
Источники дополнительных сведений