- •4.9.1. Изменяемость
- •4.9.2. Классы операций
- •98 Глава 4
- •4.9.3. Полнота
- •100 Глава 4
- •4.9.5. Операции egual, similar и copy
- •102 Глава 4
- •104 Глава 4
- •5. Исключительные ситуации
- •108 Глава 5
- •110 Глава 5
- •6.2.1. Сигнализация об исключительных ситуациях
- •5.2.2. Обработка исключительных ситуаций
- •112 Глава 5
- •5.2.3. Предложение resignal
- •6.2.4. Необрабатываемые исключительные ситуации
- •114 Глава 5
- •6.2.3. Предложение resignal
- •5.2.4. Необрабатываемые исключительные ситуации
- •116 Глава 5
- •118 Глава 5
- •118 Глава 5
- •120 Глава 5
- •122 Глава 5
- •124 Глава 5
- •128 Глава 6
- •130 Глава 6
- •6.2.1. Реализация итераторов
- •6.2.2. Использование итераторов
- •132 Глава 6
- •134 Глава 6
- •136 Глава 6
- •138 Глава 6
- •140 Глава 7
- •142 Глава 7
- •7.2. Абстракция данных
- •144 Глава 7
- •146 Глава 7
- •148 Глава 7
- •150 Глава 7
- •7.4. Генераторы
- •162 Глава 7
- •154 Глава 7
- •156 Глава 7
- •162 Глава 8
- •164 Глава 8
- •166 Глава 8
- •168 Глава 8
- •170 Глава 9
- •172 Глава 9
- •174 Глава 9
- •176 Глава 9
- •9.1.3. Пример
- •178 Глава 9
- •180 Глава 9
- •182 Глава 9
- •184 Глава 9
- •186 Глава 9
- •188 Глава 9
- •190 Глава 9
- •192 Глава. 9
- •194 Глава 9
146 Глава 7
{Объявление типа представления для типа данных intqueue) type
intqueue = ^intqueiie_rep; intqueue_rep == ^г^иеие.^ет; intqueue_e!em == record val: integtr; next: intqtieue_rep; end;
{Начало реализации операций для типа данных intqueue} tunction q_new: intqueue; var q; intqueue; begin new (q); qf :== nil; q_new := q end {функция q_new};
function qJsempty (q: intqueue): boolean; begin qJsempty := (q^ = nil) end {функция qJsempty};
procedure q_append (q: intqueue; e: integer); var last_elem, elem: intqueue_rep; begin new (elem); ^ет^.уа) := e; elernf.next .'== nil; if qJsempty (q) then q^ := elem else begin last_elem :== qf; while last.elernf.next () nil do
last_elem :== last.elemf.next; last.elem^.next :== elem end;
end {процедура q_append}; tunction q_remfirst (q: intqueue): Integer; var oldq: infqueue_rep; begin
if qJsempty (q) (He удовлетворяются требования предложения requires} then failure (' К фрикции q_remfirst обратились с пустой очередью") else begin q.rernfirst :== q^.val; oldq :== qf;
qt ••= qTt-"ext:
dispose (oldq) {Освободить пространство, занимаемое удаленным элементом} end
end {функция q_rennfirst); procedure q_destroy (q: intqlieue) •var next.elem, old_elem: intqueue_rep; begin next.elem :•=. <\\', while next_elem ( ) nil do begin old_elem := next_elem; next_elem :=г next_elem•l•. next; dispose (old^elem); end; dispose (q) end {процедура q_destroy}; {Конец реализации операций типа данных intqueue}
Рис. 7,2. Реализация операций типа данных intqueue.
Использование языка Паскаль
Рис. 7.3. Очереди ql и q2 совместно используют одну и ту же очередь.
к памяти через повисающую ссылку, то может быть прочитана бессмысленная информация. Еще хуже модификации, сделанные через повисающие ссылки. Они могут нарушить непротиворечивость других объектов. Хотя при реализации па языке Паскаль можно обнаружить повисающие ссылки, такое обнаружение трудоемко и поэтому обычно не делается. На рис. 7.2 приведена реализация типа данных intqueue, включая и операцию destroy.
По нашему соглашению следует, что каждый абстрактный тип, который представляется некоторым указателем, гарантирует, что присваивание абстрактных значений имеет тот же самый смысл, что и присваивание на языке CLU. Это не эквивалентно тому присваиванию, которое существует в языке Паскаль для встроенных в него типов. На языке Паскаль, например, присваивание массива а 1: == а2 приводит к копированию массива а2. Последующие изменения в массиве а2 не влияют на массив а1. Если, с другой стороны, мы напишем ql: = q2, где ql и q2 являются очередями целых чисел типа intqueue, то будет копироваться только указатель, а очереди ql и q2 будут совместно использовать очередь intqueue.
Важно, чтобы это совместное использование правильно работало. Последующие изменения в очереди q2 должны отражаться в очереди q), и наоборот. Мы достигаем этого, употребляя еще один уровень косвенного указания в представлении. Вместо того чтобы указывать непосредственно на первый элемент очереди, заголовки очередей ql и q2 указывают на некоторый указатель, который уже указывает на первый элемент очереди (рис. 7.3). Это позволяет нам удалять первый элемент из очереди и отражать это для обеих очередей ql и q2. Такое косвенное указание могло бы быть также сделано посредством некоторой записи, а не просто указателя. Например, предположим, что мы решили хранить размер очереди в представлении (это было бы полезным, если бы очереди целых чисел intqueue имели операцию size). Тогда бы мы задали следующее: intqueue_rep = record size: integer; first; lintqueue_ elem; end
