
- •X,y : real;
- •Virtual.
- •656535 И должен быть уникальным среди индексов других динамичес-
- •Inherited; в методах объектного типа, не имеющего предка, ключе-
- •Integer. Обратите внимание на использование в описаниях tCharVal
- •Глава 5. Переменные и типизированные константы
- •Value: 0; Min: -999; Max: 999);
- •Value: Direction;
B.Pascal 7 & Objects/LR - 42 -
Вещественные типы
─────────────────────────────────────────────────────────────────
К вещественному типу относится подмножество вещественных чи-
сел, которые могут быть представлены в формате с плавающей точкой
с фиксированным числом цифр. Запись значения в формате с плаваю-
щей запятой обычно включает три значения - m, b и e - таким обра-
зом, что m x b^e=n, где b всегда равен 2, а m и e являются цело-
численными значениями в диапазоне вещественного типа. Эти
значения m и e далее определяют диапазон представления и точность
вещественного типа.
Имеется пять видов вещественных типов: вещественное (Real),
с одинарной точностью (Single), с двойной точностью (Double), с
повышенной точностью (Extended) и сложное (Comp). Действия над
типами с одинарной точностью, с двойной точностью и с повышенной
точностью и над сложным типом могут выполняться только при нали-
чии числового сопроцессора 8087 (который был описан ранее).
Вещественные типы различаются диапазоном и точностью связан-
ных с ними значений (см. Таблицу 4.2).
Диапазон представления
и десятичные цифры для вещественных типов Таблица 4.2
┌───────────────────────┬───────────────────────────┬───────────┐
│ Тип │ Диапазон │ Цифры │
├───────────────────────┼───────────────────────────┼───────────┤
│ вещественное │2.9x10^-39 .. 1.7x10^38 │от 11 до 12│
│ (Real) │ │ │
├───────────────────────┼───────────────────────────┼───────────┤
│ с одинарной точностью │1.5x10^-45 .. 3.4x10^38 │от 7 до 8 │
│ (Single) │ │ │
├───────────────────────┼───────────────────────────┼───────────┤
│ с двойной точностью │5.0x10^-324 .. 1.7x10^308 │от 15 до 16│
│ (Double) │ │ │
├───────────────────────┼───────────────────────────┼───────────┤
│ с повышенной точностью│1.9x10^-4951 .. 1.1x10^4932│от 19 до 20│
│ (Extended) │ │ │
├───────────────────────┼───────────────────────────┼───────────┤
│ сложный тип │ -2^63 + 1 .. 2^63 - 1 │ │
│ (Comp) │ │ │
└───────────────────────┴───────────────────────────┴───────────┘
Примечание: Сложный тип содержит только целочисленные
значения в диапазоне от -2^63+1 до 2^63-1, что приблизи-
тельно равно -9.2x10^18 и 9.2x10^18.
Borland Pascal поддерживает две модели генерации кода для
выполнения действий над вещественными типами: программную для чи-
сел с плавающей точкой и аппаратную для чисел с плавающей точкой.
Выбор соответствующей модели осуществляется с помощью директивы
компилятора $N.
B.Pascal 7 & Objects/LR - 43 -
Программная поддержка чисел с плавающей точкой
─────────────────────────────────────────────────────────────────
В состоянии {$N-}, которое устанавливается по умолчанию, ге-
нерируемый код выполняет все вычисления с вещественными типами
программно, через вызов подпрограмм библиотеки исполняющей систе-
мы. Из-за соображений скорости и размера кода в этом состоянии
допускаются только действия над переменными типа real (веществен-
ное). Любая попытка оттранслировать операторы, выполняющие дейс-
твия над типами с одинарной точностью, с двойной точностью, с по-
вышенной точностью и над сложными типами, вызовет сообщение об
ошибке.
Аппаратная поддержка чисел с плавающей точкой
─────────────────────────────────────────────────────────────────
В состоянии {$N+} генерируемый код выполняет все вычисления
над вещественными типами с помощью числового сопроцессора 8087.
Это состояние позволяет использовать все пять вещественных типов,
однако оно требует наличия сопроцессора 8087 на этапе компиляции
и выполнения.
Borland Pascal включает в себя библиотеки исполняющей систе-
мы, которые автоматически эмулируют программным путем сопроцессор
80х87, если при выполнении прикладной программы DOS реального или
защищенного режима он отсутствует. Для определения того, следует
ли в программу DOS включить эмулятор сопроцессора 80x87, исполь-
зуется директива компилятора $E. Если вы создает прикладную прог-
рамму для реального или защищенного режима DOS, и сопроцессор
80х87 отсутствует, разрешение директивы компилятора $E обеспечи-
вает полную программную эмуляцию сопроцессора 80x87. Для программ
Windows директива $E не действует, так как Windows обеспечивает
собственные подпрограммы эмуляции.
Примечание: Более детальное описание генерации кода
при аппаратной поддержке чисел с плавающей запятой вы може-
те найти в Главе 15 "Использование сопроцессора 8087 в
Borland Pascal".
B.Pascal 7 & Objects/LR - 44 -
Строковые типы
─────────────────────────────────────────────────────────────────
Значением строкового типа является последовательность симво-
лов с динамическим атрибутом длины (в зависимости от действитель-
ного числа символов при выполнении программы) и постоянным атри-
бутом размера в диапазоне от 1 до 255. Текущее значение атрибута
длины можно получить с помощью стандартной функции Length.
┌──────┐
строковый тип ───>│string├──┬──────────────────────────────>
└──────┘ │ ^
│ ┌───┐ ┌─────┐ ┌───┐ │
└─>│ [ ├──>│целое├──>│ ] ├─┘
└───┘ │ без │ └───┘
│знака│
└─────┘
Примечание: Операторы работы со строковыми типами опи-
сываются разделах "Строковые операторы" и "Операторы отно-
шений" Главы 6.
Отношение между любыми двумя строковыми значениями устанав-
ливается согласно отношению порядка между значениями символов в
соответствующих позициях. В двух строках разной длины каждый сим-
вол более длинной строки без соответствующего символа в более ко-
роткой строке принимает значение "больше"; например, 'Xs' больше,
чем 'X'. Нулевые строки могут быть равны только другим нулевым
строкам, и они являются наименьшими строковыми значениями.
Примечание: Стандартные процедуры и функции для работы
со строковыми типами описаны в разделе "Строковые процедуры
и функции".
К символам в строках можно обращаться как к элементам масси-
ва. См. раздел "Массивы, строки и индексы" в Главе 5.
К идентификатору строкового типа и к ссылке на переменную
строкового типа можно применять стандартные функции Low и High. В
этом случае функция Low возвращает 0, а High возвращает атрибут
размера (максимальную длину) данной строки.
Параметр-переменная, описанная с помощью идентификатора
OpenString и ключевого слова string в состоянии {$P+}, является
открытым строковым параметром. Открытые строковые параметры поз-
воляют передавать одной и той же процедуре или функции строковые
переменные изменяющегося размера.
Примечание: Открытые строковые параметры описываются в
Главе 9.
B.Pascal 7 & Objects/LR - 45 -
Структурные типы
─────────────────────────────────────────────────────────────────
Структурный тип, характеризуемый методом структурирования и
типами своих компонентов, имеет более одного значения. Если тип
компонента является структурным, то получаемый в результате
структурный тип имеет более одного уровня структурирования.
Структурный тип может иметь неограниченные уровни структурирова-
ния.
┌───────────────┐
структурный ──┬────────────────┬──>│ тип массив ├─────>
тип │ ┌────────┐ ^ │ └───────────────┘ ^
└─>│ packed ├─┘ │ ┌───────────────┐ │
└────────┘ ├──>│ множественный ├──┤
│ │ тип │ │
│ └───────────────┘ │
│ ┌───────────────┐ │
├──>│ файловый тип ├──┤
│ └───────────────┘ │
│ ┌───────────────┐ │
├──>│ тип "запись" ├──┤
│ └───────────────┘ │
│ ┌───────────────┐ │
└──>│ объектный тип ├──┘
└───────────────┘
Слово packed (упакованный) в описании структурного типа тре-
бует от компилятора уплотнить хранимые данные, даже за счет
уменьшения скорости доступа к компоненту в переменной этого типа.
Слово packed не имеет никакого действия в Borland Pascal, пос-
кольку упаковка выполняется здесь автоматически всюду, где это
возможно.
B.Pascal 7 & Objects/LR - 46 -
Типы массив
─────────────────────────────────────────────────────────────────
Массивы содержат фиксированное число элементов одного типа,
так называемого типа элемента. На приводимой ниже синтаксической
диаграмме тип элемента следует за словом of.
┌───────┐ ┌───┐ ┌───────┐ ┌───┐ ┌────┐ ┌─────┐
тип ──>│ array ├─>│ [ ├───>│ тип ├─┬─>│ ] ├─>│ of ├─>│ тип ├>
массив └───────┘ └───┘ ^ │индекса│ │ └───┘ └────┘ └─────┘
│ └───────┘ │
│ ┌───┐ │
└────┤ , │<──┘
└───┘
тип ┌────────────────┐
индекса ───>│ порядковый тип ├───>
└────────────────┘
В индексных типах, по одному для каждой размерности массива,
указывается число элементов. Допустимыми индексными типами явля-
ются все порядковые типы, за исключением длинного целого и подди-
апазонов длинного целого. Массив может быть проиндексирован по
каждой размерности всеми значениями соответствующего индексного
типа; число элементов поэтому равно числу значений в каждом ин-
дексном типе. Число размерностей не ограничено.
Приведем пример типа массив:
array[1..100] of Real
Если тип элемента в типе массив также является массивом, то
результат можно рассматривать как массив массивов или как один
многомерный массив. Например,
array[boolean] of array[1..100] of array[Size] of Real
интерпретируется компилятором точно так же, как массив:
array[boolean,1..10,Size] of Real
Кроме того, можно записать выражение:
packed array[1..10] of packed array[1..8] of Boolean
как
packed array[1..10,1..8] of Boolean
Для доступа к элементам массива необходимо указать идентифи-
катор массива с одним или несколькими индексами в скобках (см.
раздел "Массивы, строки и индексы").
Тип массив, имеющий вид:
B.Pascal 7 & Objects/LR - 47 -
packed array[M..N] of Char
где M меньше N, называется упакованным строковым типом (слово
packed можно опустить, поскольку оно не оказывает действия в
Borland Pascal). Упакованный строковый тип имеет некоторые свойс-
тва, не характерные для других типов массив (см. раздел "Тождест-
венные и совместимые типы" далее в этой главе).
Массив вида:
array[0..X] of Char
где X - положительное целое число, называется массивом с нулевой
базой. Массивы с нулевой базой используются для хранения строк с
завершающим нулем, и, когда разрешен расширенный синтаксис (с по-
мощью директивы компилятора {$X+}), символьный массив с нулевой
базой совместим со значением типа PChar. Полностью эта тема об-
суждается в Главе 18 "Использование строк с завершающим нулем".
Параметр, описанный с помощью синтаксиса array of T, называ-
ется открытым строковым параметром. Открытые строковые параметры
позволяют передавать одной и той же процедуре или функции строко-
вые переменные изменяющегося размера.
Примечание: Открытые строковые параметры описываются в
Главе 9.
B.Pascal 7 & Objects/LR - 48 -
Типы запись
─────────────────────────────────────────────────────────────────
Тип запись содержит установленное число элементов или полей,
которые могут быть различных типов. Описание типа запись указыва-
ет тип каждого поля и идентификатор, который именует поле.
┌────────┐ ┌─────┐
тип запись ───>│ record ├──┬────────────────>│ end ├──>
└────────┘ │ ┌────────┐ ^ └─────┘
└─>│ список ├─┘
│ полей │
└────────┘
список ┌────────────┐
полей┬─>│ фиксирован-├─┬────────────────────────────┬──────────>
│ │ ная часть │ │ ┌───┐ ┌────────────┐ ^ │ ┌───┐ ^
│ └────────────┘ └─>│ ; ├───>│ вариантная ├─┘ └─>│ ; ├─┘
│ └───┘ ^ │ часть │ └───┘
└──────────────────────────┘ └────────────┘
┌─────────────────┐ ┌───┐ ┌─────┐
фиксированная ────>│ список ├──>│ : ├───>│ тип ├──┬──>
часть ^ │ идентификаторов │ └───┘ └─────┘ │
│ └─────────────────┘ │
│ │
│ ┌───┐ │
└────────────┤ ; │<────────────────────────┘
└───┘
Фиксированная часть типа запись содержит список фиксирован-
ных полей вместе с идентификатором и типом для каждого поля. Каж-
дое поле содержит информацию, которая всегда отыскивается одним и
тем же способом.
Приведем пример типа запись:
record
year: integer; { год }
month: 1..12; { месяц }
day: 1..31; { число }
end
B.Pascal 7 & Objects/LR - 49 -
В вариантной части, изображенной на синтаксической диаграмме
описания типа запись, память распределяется более чем для одного
списка полей, поэтому доступ к информации может быть осуществлен
более чем одним способом. Каждый список полей является вариантом.
Варианты налагаются друг на друга в памяти, поэтому в любое время
возможен доступ ко всем полям во всех вариантах.
вариантная часть
│ ┌────┐ ┌────────┐ ┌──┐ ┌───────┐
└─>│case├─┬───────────────────>│тип поля├─>│of├────>│вариант├─┬>
└────┘ │ ^ │признака│ └──┘ ^ └───────┘ │
│ ┌───────┐ ┌───┐ │ └────────┘ │ ┌───┐ │
└>│иденти-├>│ : ├─┘ └────┤ ; │<───┘
│фикатор│ └───┘ └───┘
└───────┘
┌────────────────┐
тип поля ────>│ идентификатор ├────>
признака │порядкового типа│
└────────────────┘
┌─────────┐ ┌───┐ ┌───┐ ┌───┐
вариант ────>│константа├─┬─>│ : ├─>│ ( ├─┬─────────────>│ ) ├──>
^ └─────────┘ │ └───┘ └───┘ │ ^ └───┘
│ ┌───┐ │ │ │
└────┤ , │<────┘ │ ┌──────┐ │
└───┘ └─>│список├─┘
│полей │
└──────┘
Вы можете видеть на диаграмме, что каждый вариант идентифи-
цирован по крайней мере одной константой. Все константы должны
быть отличными друг от друга и иметь порядковый тип, совместимый
с типом поля признака. Доступ к вариантным и фиксированным полям
один и тот же.
В вариантной части можно указать необязательный идентифика-
тор - идентификатор признака поля. При наличии идентификатора
признака поля он становится идентификатором дополнительного фик-
сированного поля записи - поля признака. Программа может исполь-
зовать значение поля признака для указания, какой вариант являет-
ся активным в настоящий момент. Без указания поля признака
программа выбирает вариант по другому критерию.
Ниже приводятся несколько примеров типов запись:
record
firstName,lastName : string[40];
birthDate : Date;
case citizen : boolean of
True : (birthPlace: string[40]);
False : (country : string[20];
B.Pascal 7 & Objects/LR - 50 -
entryPort : string[20];
entryDate : Date;
exitDate : Date);
end
record
X,y : real;
case kind : Figure of
rectangle : (height,wigth: real); { прямоугольник }
triangle : (size1,side2,angle: real); { треугольник }
circle : (radius: real); { круг }
end
Объектные типы
─────────────────────────────────────────────────────────────────
Объектный тип является структурой, состоящей из фиксирован-
ного числа компонентов. Каждый компонент является либо полем, со-
держащим данные строго определенного типа, либо методом, выполня-
ющим операции над объектом. По аналогии с описанием переменных,
описание поля указывает тип данного этого поля и идентификатор,
именующий поле: по аналогии с описанием процедуры или функции,
описание метода указывает заголовок процедуры, функции, конструк-
тора или деструктора.
Объектный тип может наследовать компоненты другого объектно-
го типа. Если T2 наследует от T1, то T2 является потомком T1, а
T1 является родителем T2.
B.Pascal 7 & Objects/LR - 51 -
Наследование является транзитивным, то есть если T3 наследу-
ет от T2, а T2 наследует от T1, то T3 наследует от T1. Область
(домен) объектного типа состоит из него самого и из всех его нас-
ледников.
┌──────┐ ┌────────────────┐
тип объекта──>│object├─┬───────────────────>│список компонент├─┐
└──────┘ │ ┌────────────┐ ^ └────────────────┘ │
└─>│Hаследование├─┘ │
└────────────┘ │
┌───────────────────────────────────────────┘
│ ┌───┐
└─┬──────────────────────────────────┬─┤end├>
│ ┌───────┐ ┌────────────────┐ │ └───┘
└──>│private├──>│список компонент├─┘
└───────┘ └────────────────┘
┌───┐ ┌─────────────────────────────┐ ┌───┐
наследование ──>│ ( ├─>│идентификатор объектного типа├─>│ ) ├──>
└───┘ └─────────────────────────────┘ └───┘
список компонент ──┬─────────────────┬───────────────────>
│ ┌────────┐ ^ │ ┌─────────┐ ^
└─>│ список ├──┘ └─>│ список ├──┘
│ полей │ │ методов │
└────────┘ └─────────┘
┌──────────────────────┐ ┌───┐ ┌────┐ ┌───┐
список полей ───>│cписок идентификаторов├─>│ : ├─>│type├>│ ; ├┬>
^ └──────────────────────┘ └───┘ └────┘ └───┘│
│ │
└───────────────────────────────────────────────┘
┌─────────┐ ┌───┐
список методов ──>│заголовок├─┬──────────────────────────┤ ; ├┬─>
^ │ метода │ │ ┌───┐ ┌───────┐ ^└───┘│
│ └─────────┘ └>│ ; ├─>│virtual├┬───────┘ │
│ └───┘ └───────┘│ ^ │
│ │ └────────┐│
│ │ ┌─────────┐││
│ └>│ целая ├┘│
│ │константа│ │
│ └─────────┘ │
└──────────────────────────────────────────────┘
┌────────────────────────┐
заголовок метода ────┬───>│ заголовок процедуры ├──────>
│ └────────────────────────┘ ^
│ ┌────────────────────────┐ │
├───>│ заголовок функции ├──┤
│ └────────────────────────┘ │
│ ┌────────────────────────┐ │
B.Pascal 7 & Objects/LR - 52 -
├───>│ заголовок конструктора ├──┤
│ └────────────────────────┘ │
│ ┌────────────────────────┐ │
└───>│ заголовок деструктора ├──┘
└────────────────────────┘
Следующий исходный код приводит пример описания объектного
типа. Далее во всей этой главе на данное описание будут делаться
ссылки.
type
Point = object
X, Y: integer;
end;
Rect = object
A, B: TPoint;
procedure Init(XA, YA, XB, YB: Integer);
procedure Copy(var R: TRectangle);
procedure Move(DX, DY: Integer);
procedure Grow(DX, DY: Integer);
procedure Intersect(var R: TRectangle);
procedure Union(var R: TRectangle);
function Contains(P: Point): Boolean;
end;
StringPtr = ^String;
FieldPtr = ^TField;
TField = object
X, Y, Len: Integer;
Name: StringPtr;
constructor Copy(var F: TField);
constructor Init(FX, FY, FLen: Integer; FName: String);
destructor Done; virtual;
procedure Display; virtual;
procedure Edit; virtual;
function GetStr: String; virtual;
function PutStr(S: String): Boolean; virtual;
end;
StrFieldPtr = ^TStrField;
StrField = object(TField)
Value: PString;
constructor Init(FX, FY, FLen: Integer; FName: String);
destructor Done; virtual;
function GetStr: String; virtual;
function PutStr(S: String): Boolean;
virtual;
function Get: string;
procedure Put(S: String);
end;
B.Pascal 7 & Objects/LR - 53 -
NumFieldPtr = ^TNumField;
TNumField = object(TField)
private
Value, Min, Max: Longint;
public
constructor Init(FX, FY, FLen: Integer; FName: String;
FMin, FMax: Longint);
function GetStr: String; virtual;
function PutStr(S: String): Boolean; virtual;
function Get: Longint;
function Put(N: Longint);
end;
ZipFieldPtr = ^TZipField;
ZipField = object(TNumField)
function GetStr: String; virtual;
function PutStr(S: String): Boolean;
virtual;
end;
В отличие от других типов, объектные типы могут описываться
только в разделе описаний типов, находящемся на самом внешнем
уровне области действия программы или модуля. Таким образом, объ-
ектные типы не могут описываться в разделе описаний переменных
или внутри блока процедуры, функции или метода.
Тип компоненты файлового типа не может иметь объектный тип
или любой структурный тип, содержащий компоненты объектного типа.
B.Pascal 7 & Objects/LR - 54 -
Компоненты и область действия
─────────────────────────────────────────────────────────────────
Область действия идентификатора компоненты простирается за
пределы объектного типа. Более того, область действия идентифика-
тора компонента простирается сквозь блоки процедур, функций,
конструкторов и деструкторов, которые реализуют методы объектного
типа и его наследников. Исходя из этих соображений, написание
идентификатора компоненты должно быть уникальным внутри объектно-
го типа и внутри всех его наследников, а также внутри всех его
методов.
Область действия идентификатора компонента, описанного в
части private описания типа, ограничивается модулем (программой),
которая содержит описание объектного типа. Другими словами, част-
ные (private) компоненты-идентификаторы действуют, как обычные
общедоступные идентификаторы в рамках модуля, который содержит
описание объектного типа, а вне модуля любые частные компоненты и
идентификаторы неизвестны и недоступны. Поместив в один модуль
связанные типы объектов, можно сделать так, что эти объекты смо-
гут обращаться к частным компонентам друг друга, и эти частные
компоненты будут неизвестны другим модулям.
В описании объектного типа заголовок метода может задавать
параметры описываемого объектного типа, даже если описание еще не
полное. Это иллюстрируется методами Copy, Intersect и Union типа
TRectange в предыдущем примере.
Методы
─────────────────────────────────────────────────────────────────
Описание метода внутри объектного типа соответствует опере-
жающему описанию метода (forward). Таким образом, где-нибудь пос-
ле описания объектного типа, но внутри той же самой области дейс-
твия, что и область действия описания объектного типа, метод дол-
жен реализоваться путем определения его описания.
Если требуется уникальный идентификатор метода, то использу-
ется уточненный идентификатор метода. Он состоит из идентификато-
ра типа объекта, за которым следуют точка и идентификатор метода.
Как и любому другому идентификатору, идентификатору уточненного
метода, если требуется, могут предшествовать идентификатор пакета
и точка.
уточненный идентификатор метода
│ ┌─────────────────────────────┐ ┌───┐ ┌────────────────────┐
└─>│идентификатор объектного типа├>│ . ├>│идентификатор метода├>
└─────────────────────────────┘ └───┘ └────────────────────┘
Виртуальные методы
─────────────────────────────────────────────────────────────────
По умолчанию, методы являются статическими, однако они мо-
B.Pascal 7 & Objects/LR - 55 -
гут, за исключением конструкторов, быть виртуальными (посредством
включения директивы virtual в описание метода). Компилятор разре-
шает ссылки на вызовы статических методов во время процесса ком-
пиляции, тогда как вызовы виртуальных методов разрешаются во вре-
мя выполнения. Это иногда называют поздним связыванием.
Если объектный тип объявляет или наследует какой-либо вирту-
альный метод, то переменные этого типа должны быть инициализиро-
ваны посредством вызова конструктора перед вызовом любого вирту-
ального метода. Таким образом, объектный тип, который описывает
или наследует виртуальный метод, должен также описывать или нас-
ледовать по крайней мере один метод-конструктор.
Объектный тип может переопределять любой из методов, которые
он наследует от своих родителей. Если описание метода в потомке
указывает тот же идентификатор метода, что и описание метода в
родителе, то описание в потомке переопределяет описание в родите-
ле. Область действия переопределяющего метода расширяется до сфе-
ры действия потомка, в котором этот метод был введен, и будет ос-
таваться таковой, пока идентификатор метода не будет переопреде-
лен снова.
Переопределение статического метода не зависит от изменения
заголовка метода. В противоположность этому, переопределение вир-
туального метода должно сохранять порядок, типы и имена парамет-
ров, а также типы результатов функций, если таковые имеются. Бо-
лее того, переопределение опять же должно включать директиву