
- •X,y : real;
- •Virtual.
- •656535 И должен быть уникальным среди индексов других динамичес-
- •Inherited; в методах объектного типа, не имеющего предка, ключе-
- •Integer. Обратите внимание на использование в описаниях tCharVal
- •Глава 5. Переменные и типизированные константы
- •Value: 0; Min: -999; Max: 999);
- •Value: Direction;
Inherited; в методах объектного типа, не имеющего предка, ключе-
вое слово inherited использоваться не может.
Неявный параметр Self активизации уточненного метода стано-
вится параметром Self метода, содержащего вызов. Активизация
уточненных методов не предусматривает механизма диспетчеризации
виртуальных методов - вызов будет всегда статическим и всегда вы-
зывает заданный метод.
Активизация уточненного метода используется обычно в переоп-
ределяющем методе для активизации переопределяющего метода. С
учетом описанных выше типов приведем некоторые примеры активиза-
ции уточненных методов:
constructor TNumField.Init(Fx, FY, Flen: Integer;
FName: String; FMin, FMax: Longint);
begin
inherited Init(FX, FY, FLen, FName);
Value := 0;
Min := FMin;
Max := FMax;
end;
function TZipField.PutStr(S: String): Boolean;
begin
PutStr := (Length(S) = 5) and TNumField.PutStr(S);
end;
Как показывают эти примеры, активизация уточненных методов
позволяет переопределяющему методу "вновь использовать" код мето-
B.Pascal 7 & Objects/LR - 61 -
да, который он переопределяет.
Множественные типы
─────────────────────────────────────────────────────────────────
Диапазон значений множественного типа представляет собой
мощность множества для определенного порядкового типа (базового
типа). Каждое возможное значение множественного типа является
подмножеством возможных значений базового типа.
Переменная множественного типа может принимать как все зна-
чения множества, так и ни одного.
┌─────┐ ┌────┐ ┌────────────────┐
тип множество ───>│ set ├───>│ of ├───>│ порядковый тип ├───>
└─────┘ └────┘ └────────────────┘
Базовый тип не должен иметь более 256 возможных значений, и
порядковые значения верхней и нижней границы базового типа должны
не превышать диапазона от 0 до 255. В силу этого базовый тип мно-
жества не может быть коротким целым (Shortint), целым (Integer),
длинным целым (Longint) или словом (Word).
Примечание: Операции над множественными типами описыва-
ются в разделе "Операции над множествами" в Главе 6. В раз-
деле "Описатели множеств" показано, как определять значения
множества.
Любой множественный тип может принимать значение [], которое
называется пустым множеством.
B.Pascal 7 & Objects/LR - 62 -
Файловые типы
─────────────────────────────────────────────────────────────────
Файловый тип состоит из линейной последовательности компо-
нентов, которые могут иметь любой тип за исключением файлового
типа или структурного типа, содержащего компонент с файловым ти-
пом. Число компонентов описанием файлового типа не устанавливает-
ся.
┌──────┐ ┌────┐ ┌─────┐
файловый тип ───>│ file ├──┬─>│ of ├───>│ тип ├─────>
└──────┘ │ └────┘ └─────┘ ^
└─────────────────────┘
Если слово of и тип компонента опущены, то тип обозначает
нетипизированный файл. Нетипизированные файлы представляют собой
каналы ввода-вывода нижнего уровня, в основном используемые для
прямого доступа к любому файлу на диске, независимо от его внут-
реннего формата.
Стандартный файловый тип Text определяет файл, содержащий
символы, упорядоченные в строки. Текстовые файлы используют спе-
циальные процедуры ввода-вывода, которые описываются в Главе 14
"Ввод и вывод".
B.Pascal 7 & Objects/LR - 63 -
Ссылочные типы
─────────────────────────────────────────────────────────────────
Cсылочный тип (указатель) определяет множество значений, ко-
торые указывают на динамические переменные определенного типа,
называемого базовым типом. Переменная ссылочного типа содержит
адрес динамической переменной в памяти.
┌───┐ ┌─────────────┐
ссылочный тип ──────>│ ^ ├───>│ базовый тип ├──>
└───┘ └─────────────┘
┌─────────────────────┐
базовый тип ────>│ идентификатор типа ├───>
└─────────────────────┘
Если базовый тип является еще не описанным идентификатором,
то он должен быть описан в той же самой части описания типов, что
и тип указатель.
Переменной-указателю можно присвоить значение с помощью про-
цедуры New, операции @ или функции Ptr. Процедура New отводит но-
вую область памяти в динамически распределяемой области для дина-
мических переменных и сохраняет адрес этой области в переменной
указателя. Операция @ ориентирует переменную-указатель на область
памяти, содержащую существующую переменную, включая и те перемен-
ные, которые имеют идентификаторы. Функция Ptr ориентирует пере-
менную-указатель на определенный адрес в памяти.
Зарезервированное слово nil обозначает константу со значени-
ем указателя, которая ни на что не указывает.
B.Pascal 7 & Objects/LR - 64 -
Тип Pointer
─────────────────────────────────────────────────────────────────
Встроенный тип Pointer обозначает нетипизированный указа-
тель, то есть указатель, который не указывает ни на какой опреде-
ленный тип. Переменные типа Pointer могут быть разыменованы: ука-
зание символа ^ после такой переменной вызывает появление ошибки.
Как и значение, обозначаемое словом nil, значения типа Pointer
совместимы со всеми другими типами указателей.
Примечание: В разделе "Указатели и динамические пере-
менные" в Главе 5 вы можете найти синтаксис ссылки на дина-
мические переменные, которые указываются с помощью указате-
ля-переменной.
Тип PChar
─────────────────────────────────────────────────────────────────
Для представления указателя на строку с завершающим нулем в
Borland Pascal имеется предопределенный тип PChar. В блоке System
данный тип описывается следующим образом:
type PChar = ^Char;
Borland Pascal поддерживает набор расширенных правил, позво-
ляющих работать со строками с завершающим нулем, используя тип
PChar. Полностью эта тема обсуждается в Главе 18 "Использование
строк с завершающим нулем".
B.Pascal 7 & Objects/LR - 65 -
Процедурные типы
─────────────────────────────────────────────────────────────────
В стандартном Паскале процедуры и функции рассматриваются
только как части программы, которые можно выполнять с помощью вы-
зова процедуры или функции. В Borland Pascal процедуры и функции
трактуются гораздо шире: здесь допускается интерпретация процедур
и функций, как объектов, которые можно присваивать переменным и
передавать в качестве параметров. Такие действия можно выполнять
с помощью процедурных типов.
В описании процедурного типа задаются параметры, а для функ-
ции - результат функции.
процедурный тип
│
│ ┌─────────┐
└┬>│procedure├─┬───────────────────────────────────────────────>
│ └─────────┘ │ ┌────────────────────────────┐ ^ ^
│ └─>│список формальных параметров├─┘ │
┌┘ └────────────────────────────┘ └─┐
│ ┌────────┐ ┌───┐ ┌─────────┐│
└>│function├┬────────────────────────────────>│ : ├>│результат├┘
└────────┘│ ┌────────────────────────────┐^ └───┘ └─────────┘
└>│список формальных параметров├┘
└────────────────────────────┘
Характерно, что синтаксис записи процедурного типа в точнос-
ти совпадает с записью заголовка процедуры или функции, только
опускается идентификатор после ключевого слова procedure или
function. Приведем некоторые примеры описаний процедурного типа:
type
Proc = procedure;
SwapProc = procedure(var X, Y: Integer);
StrProc = procedure(S: String);
MathFunc = function(X: Real): Real;
DeviceFunc = function(var F: text): Integer;
MaxFunc = function(A, B: Real; F: MathFunc): Real;
Имена параметров в описании процедурного типа играют чисто
декоративную роль - на смысл описание они не влияют.
Borland Pascal не позволяет описывать функции, которые возв-
ращают значения процедурного типа. Результат функции должен быть
строкового, вещественного, целого, символьного, булевского типа,
указателем или иметь перечислимый тип, определенный пользовате-
лем.
Процедурные значения
─────────────────────────────────────────────────────────────────
Переменной процедурного типа можно присвоить процедурное
B.Pascal 7 & Objects/LR - 66 -
значение. Процедурные значения могут быть следующими:
* значениями nil;
* ссылкой на переменную процедурного типа;
* идентификатором процедуры или функции.
В контексте процедурных значений описание процедуры или
функции можно рассматривать как специальный вид описаний конс-
тант, когда значением константы является процедура или функция.
Рассмотрим, например, следующее описание:
var
P: SwapProc;
F: MathFunc;
procedure Swap(var A, B: Integer); far;
var
Temp: Integer;
begin
Temp := A;
A := B;
B := Temp;
end;
function Tan(Angle: Real); far;
begin
Tan := Sin(Angle) / Cos(Angle);
end;
Переменным P и F можно присвоить значения следующим образом:
P := Swap;
F := Tan;
а вызовы с помощью P и F можно выполнить так:
P(I, J); { эквивалентно Swap(I, J) }
X := F(X); { эквивалентно X := Tan(X) }
Использование процедурных переменных, которым в операторе
вызова процедуры или функции присваивается значение nil, приводит
к ошибке. Значение nil предназначено для указания того, что про-
цедурная переменная не присвоена, и, так где процедурная перемен-
ная может получить значение nil, участвующие в этой процедурной
переменной вызовы процедур и функций следует подвергать проверке:
if @P <> nil then P(I, J);
Обратите внимание на использование операции @ для указания
того, что P проверяется, а не вызывается.
B.Pascal 7 & Objects/LR - 67 -
Совместимость типов
─────────────────────────────────────────────────────────────────
Чтобы они считались совместимыми, процедурные типы должны
иметь одно и то же число параметров, а параметры в соответствую-
щих позициях должны иметь тождественные типы. При определении
совместимости процедурных типов имена параметров значения не име-
ют. Значение nil совместимо с любым процедурным типом.
Чтобы использоваться в качестве процедурных значений, проце-
дуры и функции должны описываться с директивой far и компилиро-
ваться в состоянии с {$F+}. Кроме того, в качестве процедурных
значений не могут указываться стандартные процедуры и функции,
вложенные процедуры и функции, методы, процедуры и функции, опи-
санные с ключевым словом inline или interrupt.
Стандартные процедуры и функции - это подпрограммы, описан-
ные в модуле Unit, например, WriteLn, ReadLn, Chr или Ord. Чтобы
использовать в качестве процедурного значения стандартную проце-
дуру и функцию, напишите для нее "оболочку". Например, следующая
функция DSin совместима по присваиванию с описанным выше типом
MathFunc:
function FSin(X: Real): Real; far;
begin
FSin := Sin(X);
end;
Процедура или функция является вложенной, когда она описыва-
ется внутри другой процедуры или функции. Такие вложенные проце-
дуры и функции не могут использоваться в качестве процедурных
значений.
Тождественные и совместимые типы
─────────────────────────────────────────────────────────────────
Два типа могут быть тождественными, и эта тождественность
(идентичность) является обязательной в некоторых контекстах. В
других случаях два типа должны быть только совместимы или совмес-
тимы по присваиванию. Два типа являются тождественными, если они
описаны с одним идентификатором типа, или если их определения ис-
пользуют один и тот же идентификатор типа.
Тождественность типов
─────────────────────────────────────────────────────────────────
Тождественность типов требуется только для переменных факти-
ческих и формальных параметров при вызове процедур и функций.
Два типа, скажем T1 и T2, являются тождественными, если яв-
ляется истинным одно из следующих утверждений: T1 и T2 представ-
ляю собой один и тот же идентификатор типа; T1 описан как эквива-
B.Pascal 7 & Objects/LR - 68 -
лентный типу, тождественному T2.
Второе условие означает, что T1 не обязательно должен быть
описан как непосредственно эквивалентный T2. Следующие описания
типов:
T1 = integer;
T2 = T1;
T3 = integer;
T4 = T2;
означают, что T1, T2, T3, T4 и integer являются тождественными
типами. Следующие описания типов:
T5 = set of integer;
T6 = set of integer;
не определяют T5 и T6 как тождественные, поскольку set of integer
не является идентификатором типа. Две переменные, описанные в од-
ном и том же описании, например:
V1, V2: set of integer;
имеют тождественные типы, поскольку их описания не раздельны.
Описания:
V1: set of integer;
V2: set of integer;
V3: integer;
V4: integer;
означают, что V3 и V4 имеют тождественный тип, а V1 и V2 - нет.
Совместимость типов
─────────────────────────────────────────────────────────────────
Иногда, например, в выражениях и операциях сравнения, требу-
ется совместимость типов. Совместимость типов, кроме того, явля-
ется важной предпосылкой для совместимости по присваиванию.
Совместимость типов имеет место, если выполняется по крайней
мере одно из следующих условий:
* Оба типа являются одинаковыми.
* Оба типа являются вещественными типами.
* Оба типа являются целочисленными.
* Один тип является поддиапазоном другого.
* Оба типа являются отрезками одного и того же основного ти-
B.Pascal 7 & Objects/LR - 69 -
па.
* Оба типа являются множественными типами с совместимыми ба-
зовыми типами.
* Один тип является строковым типом, а другой - строковым
типом, упакованным строковым типом или типом PChar;
* Один тип - это тип Pointer, а другой - любой ссылочный
тип.
* Один тип является типом PChar, а другой - символьным мас-
сивом с нулевой базой вида array[0..X] of Char (это дейс-
твует только при разрешении директивой {$X+} расширенного
синтаксиса).
* Оба типа являются указателями идентичных типов (это дейс-
твует только при разрешении указателя с проверкой типа ди-
рективой {$X+}).
* Оба типа являются процедурными с идентичными типами ре-
зультатов, одинаковым числом параметров и соответствием
между параметрами.
Совместимость по присваиванию
─────────────────────────────────────────────────────────────────
Совместимость по присваиванию необходима, если имеет место
присваивание значения, например, в операторе присваивания или при
передаче значений параметров.
Значение типа T1 является совместимым по присваиванию с ти-
пом T2 (то есть допустим оператор T1:=T2), если выполняется одно
из следующих условий:
* T1 и T2 имеют тождественные типы, и ни один из них не яв-
ляется файловым типом или структурным типом, содержащим
компонент с файловым типом на одном из своих уровней.
* T1 и T2 являются совместимыми порядковыми типами, и значе-
ния типа T2 попадают в диапазон возможных значений T1.
* T1 и T2 являются вещественными типами, и значения типа T2
попадают в диапазон возможных значений T1.
* T1 является вещественным типом, а T2 является целочислен-
ным типом.
* T1 и T2 являются строковыми типами.
* T1 является строковым типом, а T2 является символьным ти-
пом (Char).
B.Pascal 7 & Objects/LR - 70 -
* T1 является строковым типом, а T2 является упакованным
строковым типом.
* T1 и T2 являются совместимыми упакованными строковыми ти-
пами.
* T1 и T2 являются совместимыми множественными типами, и все
члены значения типа T2 попадают в диапазон возможных зна-
чений T1.
* T1 и T2 являются совместимыми типами указателей.
* T1 - это тип PChar, а T2 - это строковая константа (это
действует только при разрешении директивой {$X+} расширен-
ного синтаксиса).
* T1 является типом PChar, а T2 - символьным массивом с ну-
левой базой вида array[0..X] of Char (это действует только
при разрешении директивой {$X+} расширенного синтаксиса).
* T1 и T2 являются совместимыми процедурными типами.
* T1 представляет собой процедурный тип, а T2 - процедура
или функция с идентичным типом результата, идентичным чис-
лом параметров и соответствием между типами параметров.
* Объектный тип T2 совместим по присваиванию с объектным ти-
пом T1, если T2 является доменом T1.
* Тип указателя Р2, указывающий на объект типа Т3, совместим
по присваиванию с типом указателя P1, указывающим на объ-
ект T1, если T2 является доменом T1.
На этапе компиляции и выполнения выдается сообщение об ошиб-
ке, если совместимость по присваиванию необходима, а ни одно из
условий предыдущего списка не выполнено.
Раздел описания типов
─────────────────────────────────────────────────────────────────
Программы, процедуры и функции имеют для описания типов спе-
циальный раздел описания типов. Например:
type
TRange = integer;
TNumber = integer;
TColor = (red,green,blue);
TTextIndex = 1..100;
TTestValue = -99..99;
TTestList = array[TestIndex] of TestValue;
PestList = ^TTestList;
B.Pascal 7 & Objects/LR - 71 -
TDate = object
year: integer;
month: 1..12;
day: 1.. 31;
procedure SetDate(D, M, Y: Integer);
function ShowDate: String;
end;
MeasureData = record
when: Date;
count: TTestIndex;
data: TestListPtr;
end;
TMeasureList = array[1..50] of MeasureData;
TName = string[80];
TSex = (male,female);
TPersonDate = ^TPersonData;
TPersonData = record
name,firstName: TName;
age: integer;
married: boolean;
father,child,sibling: Person;
case s: Sex of
male: (bearded: boolean);
female: (pregnant: boolean);
end;
TPersonDate = array[0..SizeOf(TPersonDate)-1] of Byte;
TPeople = file of TPersonData;
В этом примере Range, Number и Integer являются тождествен-
ными типами. TTestIndex является просто совместимым и совместимым
по присваиванию, но не тождественным, с типами Number, Range и