ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 23.01.2025
Просмотров: 3179
Скачиваний: 3
3.2. Директивы видимости
Ключевая идея объектного подхода заключается в сокрытии информации. В хорошо спроектированном классе никакие изменения внутри не должны отражаться на пользователях данного класса. Директивы видимости, используемые в объектной модели языка Паскаль, позволяют ограничить доступность элементов класса.
Существует четыре уровня сокрытия информации, которые задаются директивами Private (закрытый), Public (общедоступный), Protected (защищенный) и Published (публикуемый). Наиболее строгой директивой является Private, которая ограничивает видимость атрибутов и методов класса тем модулем, в котором расположен данный класс. Директива Public наоборот, наименее строга, и обеспечивает доступ к объявлениям класса из любого модуля, имеющего доступ к данному модулю.
Директива Protected внутри модуля, в котором объявлен класс, действует аналогично директиве Private, а извне модуля – аналогично директиве Private. Однако вне модуля доступ к защищенным полям данных и методов все же возможен внутри производного класса. При создании классов директива Private должна использоваться только для полей и методов, действительно зависящих от класса. Любые поля и методы, доступ к которым из производных классов может потребоваться, должны быть объявлены в разделе Protected.
Для директивы Published правила видимости аналогичны Public, но разница между ними заключается в том, что Published указывает компилятору добавлять информацию о типе времени выполнения (Run-Time Type Information, RTTI) для всех объявлений этого раздела. Информация RTTI необходима инспектору объектов при работе с компонентами на форме в среде Borland® Delphi.
Распределим методы и поля по уровням доступности:
TFigure = class
private
fColor: Byte;
fThickness: Byte;
fCanvas: TCanvas;
public
constructor Create;
destructor Destroy; override;
procedure SetColor(Value: Byte);
procedure SetThickness(Value: Byte);
procedure PrepareCanvas;
end;
3.3. Свойства классов
Другим способом сохранения целостности объекта является применение свойств. Свойства в объектной модели языка Паскаль предназначены для обеспечения доступа к скрытым атрибутам класса. Обратимся к классу TFigure и введем свойства:
TFigure = class
private
fColor: Byte;
fThickness: Byte;
fCanvas: TCanvas;
protected
procedure SetColor(Color: Byte);
procedure SetThickness(Thickness: Byte);
property Color: Byte read fColor write SetColor;
property Thickness: Byte read fThickness write SetThickness;
public
constructor Create;
destructor Destroy;
procedure PrepareCanvas;
end;
Для определения свойств используется зарезервированное слово Property, вслед за которым задается имя свойства, затем его тип и спецификаторы чтения-записи. По принятому соглашению все методы доступа начинаются с приставки Get и Set для получения и установки значений полей соответственно. Возможны три комбинации для режима чтения-записи: запись и чтение полей (наличие директив read и write), только запись (write only) и только чтение (read only).
В примере свойство Color предназначено для модификации и чтения поля fColor, а свойство fThickness – поля fThickness. Чтение будет производиться непосредственно путем обращения к полям, а запись – с помощью методов записи SetColor и SetThickness.
Доступ к свойствам похож на обычный доступ к полям данных, однако компилятор всегда транслирует обращения к свойствам в вызовы соответствующих методов доступа. Например, присваивание:
Color:=16;
будет транслировано в вызов:
SetColor(16);
Таким образом, свойства предоставляют пользователю интерфейс, полностью скрывающий реализацию объекта, и обеспечивают контроль доступа к нему со стороны внешних объектов.
3.4. Структурированная обработка ошибок
В объектной модели языка Паскаль введено понятие исключений – ошибок времени выполнения, которые могут возникать как при некорректных действиях пользователя, так и в случае неудачного выполнения различных действий (файловых операций, запроса ресурсов операционной системы и т.д.). Средства обработки исключений позволяют упростить задачу корректного выхода из подпрограмм, их вызвавших.
Базовым классом для всех исключений является TException. Объект исключения содержит информацию о типе исключения, например, деление на ноль (класс EZeroDivide), недостаточность системных ресурсов (класс EOutOfMemory), ошибка ввода-вывода (класс EInOutError). Разветвленная структура исключений позволяет фиксировать только интересующие типы. Например, ошибки переполнения или деления на ноль относятся к классу EMathError. Поэтому, чтобы не обрабатывать все особые ситуации чисел с плавающей точкой, можно локализовать только интересующие типы, входящие в данную подгруппу.
Существуют два типа защищенных блоков, которые позволяют изменить распространение исключений. К ним относятся конструкции вида try…except…end и try…finally…end. Структурному блоку except…end передается управление только в случае появления исключения, когда требуется немедленно отреагировать на возникшую внештатную ситуацию:
try
{ охраняемый блок операторов }
except
{ Блок реакции с обработчиками особой ситуации }
end;
Внутри блока except создаются обработчики особых ситуаций для классов исключений. Обработчик имеет следующий формат:
on<класс особой ситуации>do
begin
{ код обработки особой ситуации }
end;
Объект исключения содержит текстовое описание исключения в свойстве Message и адрес исключения, доступный по методу ExceptAddr.
Содержимое finally…end выполняется в любом случае для гарантированного освобождения выделенных ресурсов:
try
{ охраняемый блок операторов }
finally
{ Блок реакции с кодом завершения }
end;
Исключения реализуются через стек вызова (список вложенных подпрограмм), и имеют ассоциированную с ним область действия. Необработанные локально (в рамках процедуры-источника), исключения передается вверх по стеку вызова к следующему блоку, который сможет его обработать. Если исключение не обрабатывается пользователем, оно передается в глобальный обработчик исключений.
Поскольку исключение по возможности следует анализировать на максимально низком уровне, то оно в основном осуществляется в блоке try…except…end. Использовать эту конструкцию следует в случае, когда при возникновении исключения требуется выполнение неотложных действий.
Обработчики исключений схожи с виртуальными методами, т.к. их можно использовать для переопределения или дополнения обработки. Если требуется активизировать стандартную обработку исключения после выполнения обработке в блоке except, можно повторно сгенерировать данное исключение с помощью директивы Raise.
Общий синтаксис повторного возбуждения исключения таков:
try
{ Охраняемые операторы }
except
on ESomeException do
begin
{ Локальная обработка особой ситуации }
raise; { повторное возбуждение исключения }
end;
end;
Схему структурированной обработки исключений можно представить в следующем виде:
try
{ получение дескриптора запрашиваемого ресурса }
try
{ выполнение потенциально опасных операций }
...
finally
{ Блок реакции с кодом завершения; освобождение ресурса }
end;
{ Блок реакции с обработчиками особой ситуации }
except
{ выделение требуемых классов исключений }
on< класс особой ситуации 1 >do
on< класс особой ситуации 2 >do
...
on< класс особой ситуации N >do
...
{ если требуется, повторное возбуждение исключительной ситуации }
raise;
end;
3.5. Применение объектов
В последующем изложении во многих примерах будут рассматриваться особенности выполнения различных алгоритмов не над фактическими данными, а над указателями, задающими расположение этих данных. Необходимость этого состоит в отделении особенностей физического и логического представления данных от обрабатываемых их алгоритмов. Разделяя данные и средства манипулирования ими, мы будем больше основное внимание уделять характеристикам алгоритмов, а не заниматься ненужной разработкой или оптимизацией методов для числовых, строковых и любых другим типов данных.
Поскольку фактически будет проводиться работа с указателями, имеет смысл использовать структуры данных, которые хранят элементы в форме указателей. Таким образом, совокупность обрабатываемых данных должна быть определенным образом организована посредством своих указателей.
Класс TList предоставляет возможность организовать работу со списком разнотипных объектов посредством указателей. Класс позволяет добавлять, удалять, перегруппировывать, сортировать и получать доступ к объектам, на которые указывают элементы списка.
Для доступа к элементу списка служит свойство класса:
List: PPointerList;
которое представляет структуру:
PPointerList = ^TPointerList;
TPointerList = array[0..MaxListSize-1] of Pointer;
Перед работой с объектом списка его необходимо создать путем вызова конструктора:
var aList: TList;
...
aList:=TList.Create;
...
try
...
finally
aList.Free;
end;
Свойство Items позволяет выполнить обращение к элементу массива через методы чтения- записи для проверки на выход за диапазон. Свойство List выполняет прямое обращение без проверки и по скорости доступа выше. Например, для сохранения в объекте aList указателя p под первым порядковым номером следует выполнить обращение:
aList.Items[0]:=p;
или поскольку свойство Items является свойством по умолчанию:
aList[0]:=p;
Свойство Count содержит общее число элементов списка. Не все элементы списка содержат фактические указатели, некоторые могут содержать адресный ноль nil. Увеличение значения свойства Count приведет к добавлению в конец списка nil-элементов, а уменьшение – удаление элементов с конца списка. Метод Pack служит для удаления всех nil-элементов из списка и коррекции значения Count.