Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Паскаль / tp3 / tp3 / 17.doc
Скачиваний:
17
Добавлен:
10.12.2013
Размер:
112.64 Кб
Скачать

Inc ax ; возвратить true

@@1: pop bp ; восстановить bp

ret8 ; извлечь параметры и выйти

Rect@ContainsENDP

code ENDS

END

Обнаружение ошибок конструктора

Как описано в Главе 16, Турбо Паскаль позволяет вам установить функцию ошибок динамически распределяемой области памяти посредством переменной HeapError модуля System. Эта функциональность поддерживается и в Турбо Паскале, однако теперь она оказывает воздействие на способ работы конструкторов.

По умолчанию, если не хватает памяти для размещения динамического экземпляра объектного типа, то вызов конструктора, использующий расширенный синтаксис стандартной процедуры New, генерирует ошибку 203 исполняющей системы. Если вы устанавливаете функцию ошибок динамической памяти, которая возвращает 1, а не стандартный результат функции 0, то вызов конструктора через New будет возвращать nil, если конструктор не сможет завершить запрос (вместо прекращения выполнения программы).

Код, который выполняет размещение и инициализацию поля таблицы виртуальных методов динамического экземпляра, является частью последовательности точки входа в конструктор. Если управление передается в точку begin операторной части конструктора, то экземпляр уже будет размещен и инициализирован. Если размещение завершилось неудачно, и если функция ошибки динамически распределяемой области памяти возвратила 1, то конструктор пропускает выполнение операторной части и возвращает указатель nil. Таким образом, указатель, который задан в расширенной процедуре New, вызывающей конструктор, будет установлен в nil (пусто).

Примечание: Имеется новая стандартная процедура Fail.

Если только управление передается в точку begin операторной части конструктора, то это гарантирует, что экземпляр объектного типа уже успешно размещен и инициализирован. Однако, сам конструктор может попытаться разместить динамическую переменную, чтобы инициализировать поле указателя экземпляра, и эта попытка может потерпеть неудачу. Если это произойдет, то конструктор с хорошо продуманным поведением должен дать обратный ход успешному размещению и в конце концов удалить размещенный экземпляр объектного типа, чтобы конечным результатом явился указатель nil. Чтобы сделать возможным этот обратный ход, Турбо Паскаль предоставляет новую стандартную процедуру Fail, которая не имеет параметров и которая может вызываться только изнутри конструктора. Вызов Fail заставляет конструктор удалить динамический экземпляр, который был размещен при входе в конструктор, и ведет к возврату указателя nil для индикации неудачной попытки.

Если динамические экземпляры размещаются с помощью расширенного синтаксиса New, то результирующее значение nil специфицированного указателя указывает на неудачную операцию. Несомненно, нет таких переменных типа указатель, которые можно было бы проверить после создания статического экземпляра или после вызова наследованного конструктора. Вместо этого, Турбо Паскаль позволяет использовать в выражениях конструкторы как функции, возвращающие результат типа boolean. Возвращаемое значение True означает успех, а False - неудачу, благодаря вызову Fail внутри конструктора.

Следующая программа предоставляет два простых объектных типа, содержащих указатели. Эта первая версия программы не использует обнаружение ошибок конструктора.

type

LinePtr = ^Line;

Line = string [79];

BasePtr = ^Base;

Base = object

L1, L2: LinePtr;

constructor Init(S1, S2: Line);

destructor Done; virtual;

procedure Dump; virtual;

end;

DerivedPtr = ^Derived;

Derived = object(base)

L3, L4: LinePtr;

constructor Init(S1, S2, S3, S4: Line);

destructor Done; virtual;

procedure Dump; virtual;

end;

var

BP: BasePtr;

DP: DerivedPtr;

constructor Base.Init(S1, S2: Line);

begin

New (L1);

New (L2);

L1^ := S1;

L2^ := S2;

end;

destructor Base.Done;

begin

Dispose(L2);

Dispose(L1);

end;

procedure Base.Dump;

begin

Writeln('B: ', L1^, ', ', L2^, '.');

end;

constructor Derived.Init(S1, S2, S3, S4: Line);

begin

Base.Init(S1, S2);

New(L3);

New(L4);

L3^ := S3;

L4^ := S4;

end;

destructor Derived.Done;

begin

Dispose(L4);

Dispose(L3);

Base.Done;

end;

procedure Derived.Dump;

begin

Writeln('D: ',L1^,', ',L2^,', ',L3^,', ',L4^,'.');

end;

begin

New(BP, Init('Турбо', 'Паскаль');

New(DP, Init('Север', 'Восток', 'Юг', 'Запад');

BP^.Dump;

DP^.Dump;

Dispose(DP, Done);

Dispose(BP, Done);

end.

Следующий пример демонстрирует, как можно переписать предыдущий пример для реализации обнаружения ошибок. Описания типов и переменных не приводятся, т.к. они остаются без изменений.

constructor Base.Init(S1, S2: Line);

begin

New(L1);

New(L2);

if (L1 = nil) or (L2 = nil) then

begin

Base.Done;

Fail;

end;

L1^ := S1;

L2^ := S2;

end;

destructor Base.Done;

begin

if L2 <> nil then

Dispose (L2);

if L1 <> nil then

Dispose(L1);

end;

constructor Derived.Init(S1, S2, S3, S4: Line);

begin

if not Base.Init(S1, S2) then

Fail;

New(L3);

New(L4);

if (L3 = nil) or (L4 = nil) then

begin

Derived.Done;

Fail;

end;

L3^ := S3;

L4^ := S4;

end;

destructor Derived.Done;

begin

if L4 <> nil then

Dispose (L4);

if L3 <> nil then

Dispose(L3);

Base.Done;

end;

{$F+}

function HeapFunc(Size: word): integer;

begin

HeapFunc := 1;

end;

{$F-}

begin

HeapError := @HeapFunc; { установить обработчик ошибок

динамически распределяемой области }

New (BP, Init ('Турбо', 'Паскаль');

New (DP, Init ('Север', 'Восток', 'Юг', 'Запад');

if (BP = nil) or (DP = nil) then

Writeln('Ошибка выделения памяти')

else

begin

BP^.Dump;

DP^.Dump;

end;

if DP <> nil then

Dispose(DP, Done);

if BP <> nil then

Dispose(BP, Done);

end.

Обратите внимание, как используются соответствующие деструкторы конструкторов Base.Init и Derived.Init для отмены любого успешного размещения перед тем, как Fail вызывается, чтобы окончательно привести к неудачному выполнению операции. Заметьте также, что в Derived.Init вызов конструктора Base.Init записан внутри выражения, благодаря чему можно проверять успешное завершение в наследуемом конструкторе.

Соседние файлы в папке tp3