Елементи програмування мовою PASCAL
· Ідентифікатори і службові слова
· Ввід та вивід.Формати виводу
· Стандартні процедури і функції
· Процедури і функції роботи із графікою
· Модулі
|
|
|
|
|
Ідентифікатори служать як імена програм, модулів, процедур, функцій, типів, змінних і констант. Ідентифікатором вважається будь-яка послідовність латинських букв або цифр, що починається з букви. Буквою вважається також символ підкреслення "_".
Наприклад, a1 _h, b123 - ідентифікатори, а 1a, ф2 - ні.
Зарезервовані слова Borland Pascal Табліця 1.1
----------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Програма на мові Pascal має наступний вигляд:
program ім'я
програми;
розділ
підключення модулів
розділ описів
begin
оператори
end.
Перший рядок називається заголовком програми і є необов'язковою.
Розділ підключення модулів починається із службового слова uses, за яким слідує список імен модулів, перераховуваних через кому.
Розділ описів може включати розділи опису змінних, констант, типів, процедур і функцій, які слідують друг за другом в довільному порядку.
Розділ підключення модулів і розділ описів можуть бути відсутній.
Операторі відділяються один від одного символом "крапка з комою".
Будь-який вираз має певний тип і після обчислення повертає деяке значення. Найпростішими виразами є змінні і константи. Складніші вирази будуються з більш простих з використанням операцій, дужок, викликів функцій, індексів і приведень типів. Дані, до яких застосовуються операції, називаються операндами.
В Pascal є наступні операції: @, not ^ * /, div, mod, and, shl, shr +, -, or, xor = > < <> <= і >=.
До арифметичних відносяться бінарні операції + - * / для дійсних і цілих чисел, бінарні операції div і mod для цілих чисел і унарні операції + і - для дійсних і цілих чисел. Вираз, що має числовий тип, називається арифметичним. Тип арифметичного виразу визначається за наступним правилом: якщо всі операнди цілі і у виразі відсутня операція розподілу /, той вираз має тип integer, в осоружному випадку вираз має тип real. Наприклад, якщо b має тип byte, з має тип 1..9, то b+c і -b мають тип integer, а 2.0+b і 1/2 - тип real.
До логічних відносяться бінарні операції and, or і xor, а також унарна операція not, операнди типу boolean, що мають, і повертаючі значення типу boolean. Вираз, що має тип boolean, називається логічним.
Операції відношення < > <= >= = <> повертають значення типу boolean і застосовуються до операндів цілого, речовинного, символьного, логічного і рядкового типів, а також до покажчиків, що типізуються. Операції = і <> також застосовуються до операндів типу роinter, до операндів, є об'єктами класів і до константи nil. При порівнянні символу і рядка символ перетвориться в рядок довжини 1.
Побітові операції and, or, not, xor, shl, shr проводять побітові маніпуляції з операндами цілого типу. Для унарної операції not результат має той же тип, що і операнд. Для решти операцій результат має тип integer. Наприклад, якщо b має тип byte і b=1, то b shl 10=1024, а not b=254.
Крім операцій відношення < > <= >= = <>, до рядкових і символьних операндів застосовна операція конкатенації (злиття) +. Її результат має рядковий тип. Наприклад, 'a'+'b'='ab'. Оскільки рядки можуть містити максимум 255 символів, то якщо зливаються рядки сумарної довжини більше 255, то програма завершується повідомленням про помилку
» Помилка: відбулося переповнювання рядка при виконанні операції "+".
Операція @ застосовується до змінної і повертає її адресу.
До покажчиків, що типізуються, застосовна операція разыменования ^: якщо p є покажчиком на тип T, то p^ - елемент типа T, на якого указує p.
Крім операцій відношення < > <= >= = <>, до покажчиків, що типізуються, застосовні арифметичні операції + і -.
Операція + застосовується до покажчика і цілого числа, що типізується: якщо p має тип ^T і указує на елемент а[k] одновимірного масиву елементів типу T, i - ціле, то p+i повертає адресу елемента а[k+i]. Операція - застосовується до двох покажчиків одного типу, що типізуються: якщо p1 і p2 указують на елементи одновимірного масиву елементів типу T, то p2-p1 повертає кількість елементів між цими покажчиками (узяте із знаком -, якщо адреса в p2 менше адреси в p1). Наприклад:
var
а: array
[1..10] integer;
p: ^integer;
begin
p:=@a[1];
for
i:=1
to 10 do begin
p^:=i;
p:=p+1;
end;
...
До множин застосовні операції + (об'єднання), - (різниця) і * (перетин):
var
s1,s2,s: set
byte;
begin
s1:=[1..4];
s2:=[2..5];
s:=s1+s2; // s=[1..5]
s:=s1-s2;
// s=[1]
s:=s1*s2; // s=[2..4]
До множин застосовні також операції відношення:
= (рівність)
<> (нерівність)
<= (вкладено)
>= (містить):
var
s1,s2,s:
set byte;
b: boolean;
begin
s1:=[1..4];
s2:=[2..5];
s:=[1,2];
b:=s1=s2; // b=False
b:=s2<>s; // b=True
b:=s<=s2;
// b=False
b:=s1>=s; // b=True
Нарешті, операція in визначає, чи належить елемент множині:
1 in
[2..5] // False
3
in
[2..5] // True
Пріоритет визначає порядок виконання операцій у виразі. Першими виконуються операції, що мають вищий пріоритет. Операції, що мають однаковий пріоритет, виконуються справа наліво.
Таблиця пріоритетів операцій
|
@, not ^ |
1 (щонайвищий) |
|
* /, div, mod, and, shl, shr |
2 |
|
+, -, or, xor |
3 |
|
= <> < > <= >=, in |
4 (низький) |
Розділ описів змінних починається із службового слова var, після якого слідують рядки вигляду
список імен змінних: тип;
Імена в списку перераховуються через кому. Наприклад:
var
а,b,c: integer;
d: real;
e,f: integer;
s,s1: string;
ch: char;
Розділ опису іменованих констант починається із службового слова const, після якого слідують рядки вигляду
ім'я константи = значення;
або
ім'я константи : тип = значення;
Наприклад:
const
Pi = 3.14; Count
= 10;
Name = 'Mike';
DigitsSet =
['0'..'9'];
Arr: array
[1..5] of
integer
= (1,3,5,7,9);
Rec: record
name: string;
age: integer end
= (name: 'Иванов';
age: 23);
Arr2: array
[1..2,1..2] of
real =
((1,2),(3,4));
Вирази після знака рівності в останніх трьох строчках називаються конструкторами констант-масивів і констант-записів і можуть бути використаний тільки при описі констант, що типізуються.
Розділ опису типів починається із службового слова type, після якого слідують рядки вигляду
ім'я типу = тип;
Наприклад:
type
myint = integer;
arr10 = array
[1..10] of
integer;
pinteger =
^integer;
A = class
i: integer;
constructor
Create(ii:
integer);
begin
i:=ii;
end;
end;
При описі рекурсивних структур даних, вказівник на тип може фігурувати раніше опису самого типу у визначенні іншого типу:
type
PNode = ^TNode;
TNode = record
data: integer;
next: PNode;
end;
При цьому важливо, щоб визначення обох типів знаходилися в одному розділі type.

type
TNode = record
data: integer;
next: ^TNode;
end;
(повідомлення про помилку: "Тип TNode повністю не визначений").
Основна програма, процедура і функція складаються із заголовка і блоку. Блоком називається розділ описів, після якого слідують оператори, укладені в операторні дужки begin/end.
Будь-який ідентифікатор, що використовується в блоці повинен бути заздалегідь описаний. В одному блоці не може бути опис двох змінних, констант або типів з одним іменем.
В блоці, проте, може бути описано декілька процедур або функцій з одним ім'ям, але з різним набором параметрів (це називається перевантаженням).
Область дії ідентифікатора (тобто місце, де він може бути використаний) простягається від моменту опису до кінця блоку, в якому він описаний. Область дії глобальноого ідентифікатора, описаного в модулі, простягається на весь модуль, а також на основну програму, до якої даний модуль підключений в розділі uses.
Ідентифікатор з тим же ім'ям, визначений у вкладеному блоці, приховує ідентифікатор, визначений в зовнішньому блоці. Наприклад, в коді
var i: integer;
procedure p;
var
i: integer;
begin
i:=5;
end;
значення 5 буде присвоєно змінній i, описаній в процедурі p; усередині ж процедури p послатися на глобальну змінну i неможливо.
Аналогічна ситуація має місце і в похідних класах: в них можна визначати поля з тими ж іменами, що і в базових класах, але тоді посилатися на полі базового класу з методу похідного класу не можна. Проте, можна посилатися на метод базового класу з методу похідного класу, використовуючи службове слово inherited:
type
A=class
i: integer;
procedure
p;
begin
i:=5;
end;
end;
B=class(A)
i: integer;
procedure
p;
begin
i:=5;
inherited
p;
end;
end;
Для виводу у вікно виведення використовуються стандартні процедури write і writeln. Вони можуть викликатися як без параметрів, так і із списком параметрів. Параметри в списку перераховуються через кому і повинні мати простий тип (окрім перечислимого типу і інтервального типу, побудованого на базі перечислюваного), або тип string, або тип вказівника. Процедура writeln після виведення своїх параметрів здійснює перехід на наступний рядок.
В процедурах виводу write і writeln після кожного значення типу, що виводиться, може указуватися формат виведення, що є двокрапкою, після якої слідує ціле число або вираз. Це число або вираз задає ширину поля виведення, тобто кількість позицій, що відводяться під значення, що виводяться. Якщо довжина значення, що виводиться, менше ширини поля виводу, то текст, що виводиться, доповнюється зліва пропусками до потрібної ширини; значення, що в результаті виводиться, вирівнюється по правому краю. Якщо довжина значення, що виводиться, більше ширини поля виведення, то формат виведення ігнорується. Речовинні і комплексні значення з форматом виведення вигляду :m завжди виводяться в експоненціальній формі.
Наприклад, якщо а, b - цілі змінні, то при виконанні операторів
а:=-2437;
b:=13555;
writeln(а:6,'Привет!':9);
writeln(b:1);
у вікно виведення буде виведений наступний текст:
-2437
Привіт!
13555
Для речовинних і комплексних значень можна також використовувати формат :m:n, де m і n - цілі значення. Значення m задає ширину поля виведення, а значення n кількість знаків після десяткової крапки. Наприклад:
writeln(-14.859:10:3); // ___-14.859
writeln(-14.859:10:5); // _-14.85900
writeln(-14.859:10:2); // ____-14.86
writeln(-14.859:10:0); // _______-15
writeln(-14.859:10:7); // -14.8590000
writeln((0,1):10:1); // _(0.0,1.0)
(тут символом “ _ “ зображені пропуски).
Для введення з клавіатури використовуються стандартні процедури read і readln. Вони можуть викликатися як без параметрів, так і з списком параметрів. Параметри в списку перераховуються через кому і повинні бути змінними простого типу (окрім перечислюваного типу, а також інтервального типу, побудованого на базі перечислюваного), або типу string. Процедура readln після введення пропускає дані до кінця поточного рядка введення.
Процедури write, writeln, read, readln - єдині, для яких можна вказувати список параметрів довільної довжини.
Для уведення-виведення в текстовий файл використовуються ті ж процедури, але як перший параметр вказується файлова змінна:
writeln(f,'abc',1,True,2.4);
· Оператор присвоєння
· Умовний оператор
· Оператор вибору
· Оператор циклу for
· Оператор циклу while
· Оператор циклу repeat
· Оператори break, continue і exit
· Оператор with
Оператор присвоєння має вигляд:
змінна:= вираз
Як змінна може бути проста змінна, розіменований вказівник, змінна з індексами або компонент змінної типу запис. Вираз повинен мати тип, або співпадаючий з типом змінної, або такий, що неявно до нього приводиться (див. Неявне приведення типів).
Умовний оператор має повну і коротку форми.
Повна форма умовного оператора виглядає таким чином:
if
<умова>
then
<оператор1>
else
<оператор2>
;
Як умова указується деякий логічний вираз. Якщо умова виявляється істинною, то виконується оператор1, в осоружному випадку виконується оператор2.
Коротка форма умовного оператора має вигляд:
if <умова> then <оператор>;
Якщо умова виявляється істинною, то виконується оператор, в осоружному випадку відбувається перехід до наступного оператора програми.
У разі конструкції вигляду
if < умова > then
if
<
умова2
> then
<оператор1>
else
<оператор2>
;
else завжди відноситься до найближчого попереднього оператора if, для якого вітка else ще не вказана. Якщо в попередньому прикладі вимагається, щоб else відносилася до першого оператора if, то необхідно використовувати складовий оператор:
if умова1
then
begin
if умова2 then оператор1;
end
else оператор2
Єднальний оператор призначений для об'єднання декількох операторів в один. Він має вигляд:
begin
операторыend
Оператори відділяються один від одного символом ";". Службові слова begin і end, оздоблюючі оператори, називаються операторними дужками.
Наприклад:
s:=0; p:=1;for
i:=1 to 10 dobegin
p:=p*i;
s:=s+pend
Перед end також може ставитися ";". В цьому випадку вважається, що останнім оператором перед end є порожнім оператором, що не виконує жодних дій.
Оператор вибору виконує одну дію з декількох залежно від значення деякого виразу, званого перемикачем. Він має наступний вигляд:
case перемикач
of
список вибору 1: оператор1;
...
список
вибору N: операторN;
else
оператор0end;
Перемикач є виразом порядкового типу (цілого, символьного, перечислимого або інтервального), а списки вибору містять константи сумісного типу. Як і в операторі if, вітка else може бути відсутньою.
Оператор case працює таким чином: якщо в одному із списків вибору знайдено поточне значення перемикача, то виконується оператор, відповідний даному списку. Якщо ж значення перемикача не знайдено ні в одному списку, то виконується оператор по вітці else або, якщо вітка else відсутня, оператор case не виконує жодних дій.
Список вибору складається або з однієї константи, або з діапазону значень вигляду а..b (константа а повинна бути менше константи b); можна також перерахувати декілька констант або діапазонів через кому:
case DayOfWeek
of
1..5:
writeln('Будній день');
6,7:
writeln('Вихідний день');end;
Списки вибору не повинні перетинатися. Наприклад, наступний фрагмент
case
i of
2,5: write(1);
4..6:
write(2);end;
приведе до помилки компіляції "Перетин діапазонів міток в операторі case".
Оператор циклу for має одну з двох форм:
for змінна:=початкове
значення to
кінцеве
значення do
оператор
або
for змінна:=
початкове значення downto
кінцеве
значення do
оператор
Текст від слова for до слова do включно називається заголовком циклу, а оператор після do - тілом циклу. Змінна після слова for називається параметром циклу. Для першої форми циклу з ключовим словом to параметр циклу міняється від початкового значення до кінцевого значення, збільшуючись всякий раз на одиницю, а для другої форми ключовим словом downto - зменшуючись на одиницю. Для кожного значення змінної-параметра виконується тіло циклу. Однократне повторення тіла циклу називається ітерацією циклу.
Значення параметра циклу після завершення циклу вважається невизначеним.
Якщо для циклу for ... to початкове значення змінної циклу більше кінцевого значення або для циклу for ... downto початкове значення змінної циклу менше кінцевого значення, те тіло циклу не виконається жодного разу.
Якщо цикл використовується в процедурі або функції, то змінна-параметр циклу повинна бути описаний як локальна.
Крапка з комою, наступна відразу після do, в Pascal вважається синтаксичною помилкою.

for i:=1
to 10
do
for i:=1
to 5
do
write(i);
Змінна-параметр циклу може мати будь-який порядковий тип (цілий, символьний, перечислюваний або інтервальний). При цьому типи початкового і кінцевого значення повинні відповідати типу параметра циклу. Наприклад:
var
en:
(red,green,blue,white);
c: char;...for
en:=red to
blue do
write(Ord(en):2);for
c:='a' to
'z' do
write(c);
Оператор циклу while має наступну форму:
while <умова>
do
оператор
<Умова> є виразом логічного типу, а оператор після do називається тілом циклу. Перед кожною ітерацією циклу умова обчислюється, і якщо вона істинна, то виконується тіло циклу, в протилежнлму випадку відбувається вихід з циклу.
Якщо <умова> завжди виявляється істинною, то може відбутися зациклювання:
while 2>1
do
write(1);
Щоб перервати програму, що зациклилася, слід використовувати комбінацію клавіш Ctrl-F2 .
Оператор циклу repeat має наступну форму:
repeat
оператори
until умова
На відміну від циклу while, умова обчислюється після чергової ітерації циклу, і якщо вона істинна, то відбувається вихід з циклу. Таким чином, оператори тіла циклу конструкції repeat, виконуються принаймні один раз.
Якщо умова завжди виявляється помилковою, то може відбутися зациклювання:
repeat
write(1);
until 2=1;
Щоб перервати програму, що зациклилася, слід використовувати комбінацію клавіш Ctrl-F2.
Оператор виклику процедури має вигляд:
ім'я процедури
або
ім'я процедури(список фактичних параметрів)
Кількість фактичних параметрів повинна співпадати з кількістю формальних, а типи фактичних параметрів повинні відповідати типам відповідних формальних.
Оператори break і continue використовуються тільки усередині циклів.
Оператор break призначений для дострокового завершення циклу. При його виконанні відбувається негайний вихід з поточного циклу і перехід до виконання оператора, наступного за циклом. Оператор continue завершує поточну ітерацію циклу, здійснюючи перехід до кінця тіла циклу. Наприклад:
flag:=False;for
i:=1 to
10 dobegin
read(x);
if
x<0 then
continue;
// пропуск поточної ітерації цикла
if
x=5 then
begin
flag:=True;
break;
// вихід з цикла
end;
end;
Використовування операторів break і continue зовні тіла циклу помилково.
Оператор exit призначений для дострокового завершення процедури або функції. Наприклад
function Analyze(x:
integer): boolean;begin
if
x<0 then
begin
Result:=False;
exit
end;
...end;
Виклик exit в розділі операторів основної програми приводить до її негайного завершення.
Оператор with дозволяє скоротити звернення до полів запису, а також до полів, методів і властивостей об'єкту. Він має вигляд:
with ім'я запису або об'єкту do оператор
або
with список імен do оператор
Усюди всередині такої конструкції можна опускати ім'я запису при зверненні до поля вказаного запису або ім'я об'єкту при зверненні до поля, методу або властивості вказаного об'єкту. Наприклад, нехай описана змінна
var
DateOfBirthday=record
Day: Integer;
Month:
Integer;
Year: Integer;
end;
Тоді присвоєння значень її полям без використання оператора with має вигляд:
DateOfBirthday.Day:=23;
DateOfBirthday.Month:=2;
DateOfBirthday.Year:=1965;
Використовування оператора with дозволяє скоротити попередній запис:
with DateOfBirthday
dobegin
Day:=23;
Month:=2;
Year:=1965;
end;
Якщо зовнішня змінна має те ж ім'я, що і поле (метод, властивість), то перевага віддається полю (методу, властивості). За наявності вкладених операторів with спочатку робиться спроба розглядати змінну як поле запису або об'єкту самого внутрішнього оператора with, потім безпосередньо охоплюючого його оператора with і т.д. Якщо оператор with містить список об'єктів, то вони розглядається справа наліво. Наприклад, якщо є опису
var
x,y,z: integer;
a: record
x,y: integer;
end;
b: record
x: integer;
end;
то фрагмент програми
with a,b
dobegin
x:=1;
y:=2;
z:=3; end;
еквівалентний фрагменту
with a
do with
b do begin
x:=1;
y:=2;
z:=3; end;
а також фрагменту
b.x:=1; a.y:=2;z:=3;
В Pascal є наступні типи:
integer (цілий)
byte (байтовий)
char
(символьний)
перечислюваний
діапазонний
boolean
(логичний)
real (дійсний)
complex
(комплексний)
string (рядковий)
array(тип
"массив")
record(тип
"запис")
pointer(тип
"вказівник")
процедурний
файловий
классовий
Типи integer, byte, char, перечислимый і діапазонний називаються порядковыми. Тільки значення цих типів можуть бути індексами масивів і фігурувати як вираз-перемикача в операторі case. Змінна-параметр циклу for також повинна мати перечислимый тип.
До всіх значень порядкового типу застосовні наступні функції:
Pred(x)
повертає значення,
передуюче x
(до якнайменшого значення
не застосовується);
Succ(x) повертає
значення, наступне за x (до
найбільшого значення не застосовується);
Ord(x) повертає
порядкове ціле значення, відповідне x.
Для цілих x
повертає саме
значення x,
для символів char
повертає їх код,
а для елементів перечислимого
типу - їх номер (нумерація
починається з нуля).
Всі порядкові типи, а також типи boolean, real і complex називаються простими типами.
Тип integer (цілий). Значення цього типу займають 4 байти і знаходяться в діапазоні від -2147483648 до 2147483647. Константа MaxInt береже значення 2147483647.
Тип byte (беззнаковий цілий). Значення цього типу займають 1 байт і знаходяться в діапазоні від 0 до 255.
Тип char (символьний). Значення цього типу займають 1 байт і є символами в кодуванні Windows. Стандартна функція Chr(x) повертає символ з кодом x. Константи цього типу можуть бути записаний у вигляді #x, де x - ціле число від 0 до 255.
Перечислімий тип визначається впорядкованим набором ідентифікаторів:
type
Season =
(Winter,Spring,Summer,Autumn); DayOfWeek =
(Mon,Tue,Wed,Thi,Thr,Sat,Sun);
Значення перечислимого типу займають 4 байти.
Інтервальний тип є підмножиною значень цілого, символьного або перечислимого типу і описується у вигляді а..b, де а - нижня, b - верхня межа інтервального типу:
var
а: 0..10; з:
'a'..'z'; d: Mon..Thr;
Тип, на основі якого будується інтервальний тип, називається базовим
Тип boolean (логічний). Змінні і константи логічного типу займають 1 байт і приймають одне з двох значень, що задаються приреченими константами True (істина) і False (брехня).
Тип real (речовинний). Значення речовинного типу займають 8 байт, містять 15-16 значущих цифр і по модулю не можуть перевершувати величини 1.7•10308. Найменше позитивне число речовинного типу рівно 5.0•10-324. Константи типу real можна записувати як у формі з плаваючою крапкою, так і в експоненціальній формі: 1.7, 0.013, 2.5e3 (2500), 1.4e-1 (0.14).
Тип complex (комплексний). Значення комплексного типу займають 16 байт. Константи цього типу записуються у вигляді (x,y), де x і у - вирази речовинного типу, речовинну і уявну частини комплексного числа, що є. Якщо змінна з має тип complex, то звернутися до її речовинної і уявної частин можна як до полів запису: c.re і c.im. Наприклад:
const ci=(0,1);
var
з:
complex;...c.re:=2*c.im;з:=ci*c+(c.im,c.re);
До змінних типу complex застосовні стандартні числові функції: abs, sin, cos, exp, ln, sqrt, а також функція conj(c), що повертає комплексно зв'язане до з, і функція carg(c), що повертає головне значення аргументу комплексного числа з. При обчисленні багатозначних функцій ln, sqrt, carg повертається головне значення і передбачається, що розріз зроблений по негативній речовинній осі, причому, верхній берег належить розрізу. Так, carg(c) повертає значення в діапазоні (-Pi,Pi].
Рядки мають тип string і складаються з не більше ніж з 255 символів. При описі
var s: string;
під змінну s відводиться 256 байт, при цьому в нульовому байті зберігається довжина рядка.
Для економії пам'яті передбачений опис вигляду
var s1: string[40];
В цьому випадку під рядок відводиться 41 байт (нульовий байт - під довжину рядка). У разі присвоєння змінного s1 рядка із понад 40 символів зайві символи відсікаються, і довжина рядка s1 вважається рівною 40.
При виконанні операції конкатенації вигляду s1+s1 результат вважається рядком типу string, тобто займає 256 байт. Проте, якщо при конкатенації результат займатиме більше 255 символів, то програма завершиться з помилкою.
До символів в рядку можна звертатися, використовуючи індекс: s[i] позначає i-тий символ в рядку. Звернення до нульового символу s[0] вважається помилковим. Щоб змінити довжину рядка, слід скористатися процедурою SetLength(). Якщо індекс i виходить за межі пам'яті, що відводиться під рядок, то видається повідомлення про помилку. Проте, якщо індекс i виходить лише за межі довжини рядка, то повідомлення про помилку не видається.
Масив є набором елементів одного типу, кожний з яких має свій номер, званий індексом (індексів може бути декілька, тоді масив називається багатовимірним). Тип масиву конструюється таким чином:
array [тип индекса1 ..., тип индексаN] базовий тип
Тип індексу обов'язково є інтервальним типом і обов'язково повинен задаватися у вигляді а..b, де а і b - константні вирази цілого, символьного або перечислюваного типу. Наприклад:
type
enum=(w1,w2,w3,w4,w5);
var
a1,a2: array
[1..10] integer;
b:
array ['a'..'z',w2..w4]
string;
з: array
[1..10]
array
[1..5] real;
Базовий тип може бути будь-яким (зокрема, він може бути типом масиву, як для змінної з).
Змінні-масиви одного типу можна присвоювати один одному, при цьому проводитиметься копіювання вмісту одного масиву в іншій:
a1:=a2;
При передачі по значенню параметра типу масив в підпрограму також проводиться копіювання вмісту массива-фактического параметра в массив-формальный параметр:
procedure p(arr:
array
[1..10] integer);
...p(a1);
Як правило, в цій ситуації копіювання вмісту масиву не потрібне, тому масив рекомендується передавати по посиланню:
procedure r(var
arr: array
[1..10] integer);
...r(a1);
До елементів масиву звертаються за допомогою змінних з індексами:
a1[3]:=a2[5];
b['f',w3]:='Hello';
з[3][4]:=3.14;
Помилка при роботі з масивами, що часто зустрічається, - вихід за межі діапазону індекса.
Запис є набором елементів різних типів, кожний з яких має своє ім'я і називається полем запису. Тип запису конструюється таким чином:
record
список полів1: тип1;
...
список полівN: типN;
end
Останній символ ";" не є обов'язковим. Наприклад:
type
Date=record
Day: 1..31;
Month: (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Осt, Nov, Dec);
Year: Integer;
end;
Тепер можна оголосити змінні типу Date:
var d1,d2: Date;
Щоб отримати доступ до полів запису, слід скористатися точковою нотацією, вказавши ім'я змінної-запису і поле, розділене крапкою:
d1.Day:=9;
d1.Month:=Sep;d1.Year:=2004;
Як і для масивів, можна скопіювати вміст полів однієї змінної-запису в іншу:
d2:=d1;
Множина є набором елементів одного порядкового типу. Елементи множини вважаються неврегульованими; кожний елемент може входити в множину не більше одного разу. Тип множини описується таким чином:
set of базовий тип
Як базове може бути будь-який порядковий тип з елементами, для яких функція Ord повертає значення в діапазоні від 0 до 255. Наприклад:
type
ByteSet = set
of byte;
CharSet = set
of char;
Digits = set
of
'0'..'9';
SeasonSet = set
of
(Winter,Spring,Summer,Autumn);
Змінна типу множина займає 16 байт і може містити декілька значень базового типу. Щоб сконструювати значення типу множина, використовується конструкція вигляду
[список значень]
де в списку можуть перераховуватися через кому або вирази базового типу, або їх діапазони у вигляді а..b, де а і b - вирази базового типу. Наприклад:
var
bs: ByteSet;
bestdays:
(Mon,Tue,Wed,Thi,Thr,Sat,Sun);
...
bs:=[1,3,5,20..25];
bestdays:=[Wed,Thr..Sun];
Значення в списку можуть бути відсутній, тоді множина є порожньою:
bs:=[];
Операція in перевіряє приналежність елемента множині:
if Wed in bestdays then ...
Для множин визначені операції: + (об'єднання), - (різниця), * (перетин), = (рівність), <> (нерівність), <= (вкладено), >= (містить). Приклади цих операцій приведені в пункті Вирази і операції.
Множини з сумісними базовими типами неявно перетворяться одне до іншого (див. пункт Неявне приведення типів). При присвоєнні множині за необхідності відбувається усікання його елементів до значень базового типу. Наприклад:
var st:
set
3..9;...
st:=[1..5,8,10,12];
// в st потраплять значення [3..5,8]
Щоб вивести значення елементів множини, необхідно перебрати всілякі значення в циклі і перевірити їх на приналежність множині за допомогою операції in:
for i:=0
to 255
do
if i
in st
then
write(i,'
');
Вказівник зберігає адресу комірки пам'яті.
Тип вказівника на тип T має форму ^T, наприклад:
type
pinteger=^integer;
var
p: ^record
r,i: real
end;
Нетипізовані вказівники описується за допомогою слова роinter.
Для доступу до елемента пам'яті, адресу якого зберігає вказівник, що типізується, використовується операція розіменування ^:
var
i:
integer;
pi: ^integer;
...
pi:=@i; // вказівнику присвоїли адресу змінної i
pi^:=5; // змінній i присвоїли 5
Операція розіменування не може бути застосованою до нетипізованого вказівника.
Вказівник, що типізується, може бути неявно перетворений до нетипізованого:
type preal=^real;
var
p: роinter;
pr: ^real;...p:=pr;
Зворотне перетворення може бути виконано тільки явно:
pr:=preal(p);
pr^:=3.14;
Вказівник можна порівнювати на рівність (=) і нерівність (<>). На додаток до цього вказівники, що типізуються, можна порівнювати, використовуючи операції < > <= >=.
Для вказівників, що типізуються, доступні також операції p+i, p-i і p2-p1, де i – ціле.
Для того, щоб відзначити той факт, що вказівник нікуди не вказує використовують стандартну константу nil (нульовий вказівник)
Текстові файли бережуть символи, розділені на рядки символами #13#10.
Для опису текстового файлу використовується стандартне ім'я типу text, а для опису файлу, що типізується, - конструкція file тип елементів:
var
f1:
file
real;
f2: text;
Файлові процедури і функції описуються в пункті Процедури і функції для роботи з файлами.
Змінні, призначені для зберігання процедур і функцій, називаються процедурними. Тип процедурної змінної має вигляд:
procedure (список параметрів)
або
function (список параметрів): тип значення, що повертається
При цьому список параметрів разом з круглими дужками можуть бути відсутній. Наприклад:
type
proc=procedure(i:
integer);
var
p1:
proc;
p2:
procedure;
f1: function:
integer;
Процедурній змінній можна привласнити процедуру або функцію з сумісним типом:
procedure my(i:
integer);begin
...end;function
f:
integer;beginend;...p1:=my;f1:=f;
Після цього можна викликати процедуру або функцію через цю процедурну змінну, користуючись звичайним синтаксисом виклику:
p1(5);
write(f1);
procedure
foreach(var
a: array
[1..100] of
real; n: integer; p:
procedure(var
r: real));
var
i: integer;
begin
for i:=1
to
n do
p(a[i]);
end;
procedure
mult2(var
r: real);
begin
r:=2*r
end;
procedure
print(var
r: real);
begin
write(r,'
');
end;
...
foreach(a,10,mult2);
// множення елементів масиву на
2
foreach(a,10,print); // вивід елементів масиву
Два типи вважаються еквівалентними (рівними), якщо співпадають їх описи. Наприклад, після описів
type Arr=array
[1..100] of
integer;var
a: Arr;
b: array
[1..100] of
integer;
можна присвоювати масиви один одному:
а:=b;
В типах записів, крім типів полів, повинні співпадати імена:
type
rec1 = record
i,j: integer
end;
rec2 = record
x,y: integer
end;...var
r1: rec1; r2:
rec2;...r1:=r2;
// ошибка!
В типах формальних параметрів процедур і функцій імена можуть не співпадати:
type
proc1 = procedure
(i: integer);
proc2 = procedure
(x:
integer);...var
p1: proc1; p2:
proc2;...p1:=p2;
// все правильно
Подібне розширене трактування еквівалентності (в порівнянні з Borland Pascal і Borland Delphi) дозволяє передавати параметри складового типу (масиви, записи, процедурний і вказівний) в процедури і функції, не визначаючи для цих параметрів новий тип:
procedure
foreach(var
a: array
[1..100] of
real; n: integer; f: function(r:
real): real);var
i:
integer;begin
for
i:=1 to
n do
a[i]:=f(a[i]);end;
В операторі присвоєння тип змінної в лівій частині може не співпадати з типом виразу в правій частині. Аналогічно тип формального параметра, передаваного по значенню, може не співпадати з типом фактичного. В цьому випадку, якщо можливо, відбувається неявне перетворення (приведення) типів.
Типи byte і integer неявно перетворяться один до одного, а також до типів real і complex.
Тип real неявно перетвориться до типу complex.
Інтервальний тип і його базовий тип неявно перетвориться один до одного, неявно перетворяться між собою також інтервальні типи, побудовані на основі одного базового типу.
Символ неявно перетвориться в рядок. Рядки різної довжини неявно перетворяться один до одного.
Покажчик на будь-який тип неявно перетвориться до вказівника роinter.
Похідний клас неявно перетвориться до базового.
Множина неявно перетвориться до іншої множини, якщо його базовий тип неявно перетвориться до базового типу цієї іншої множини.
Ім'я процедури або функції неявно перетвориться до вказівника на процедуру або функцію з параметрами тих же типів (у функції повинен також співпадати тип значення, що повертається).
В процесі виконання програми після неявного перетворення числових типів може відбутися переповнювання. Наприклад, це можливо при перетворенні типу integer в тип byte. Проте, якщо s1 і s2 - рядки і при привласненні s1:=s2 дані рядки s2 не уміщаються в рядок s1, то залишок рядка усікається без виникнення помилки.
Операнди у виразах також можуть мати різні типи. В цьому випадку звичайно менший тип неявно приводиться до більшого або обидва типи приводяться до більшого. Наприклад, якщо r має тип real, а i - тип integer, то у виразі r+i значення i спочатку приводиться до типу real, після чого виконується операція складання над двома речовинними значеннями. Якщо рядок s1 має тип string[30], а s2 - тип string[40], то у виразі s1+s2 обидва рядки приводяться до типу string і тільки потім виконується операція складання.
Вирази "менший тип" і "більший тип" в попередньому абзаці використовуються в значенні діапазону значень. Наприклад, тип set 1..9 менше типу set byte, але жоден з типів set 1..9 і set 5..15 не менше іншого.
Деякі типи не приводяться до інших неявно, проте таке перетворення має сенс. Наприклад, змінну типу char можна перетворити до значення типу byte, що є кодом символу. Змінну типу integer, що містить ненегативне значення, можна перетворити до інтервального типу, причому, це значення виступатиме номером елемента в порядковому типі.
Для перетворення виразу до нового типу використовується конструкція
ім'я нового типу(вираз)
Наприклад:
type
pinteger=^integer;
days=(mon,tue,wed,thi,fri,sat,sun);var
p: pointer;
i: integer;
en:
days;...p:=pinteger(@i);i:=integer(en):en:=days(3);
Слід звернути увагу на те, що для явного приведення типів необхідно використовувати ідентифікатор імені типу (тобто тип повинен визначатися одним словом). Наприклад, наступний запис є помилковим:
p:=^integer(@i);
Явні перетворення типів містять всі неявні. Крім того, всі порядкові типи можна явно перетворювати один до одного, всі порядкові типи можна явно перетворювати до типів real і complex, базовий клас можна явно перетворити до похідного і покажчик роinter можна явно перетворити до покажчика на будь-який тип.
Процедура або функція є послідовністю операторів, яка має ім'я, список параметрів і може бути викликана з різних частин програми. Функції, на відміну від процедур, в результаті свого виконання повертають значення. Для одноманітності функції і процедури називаються підпрограмами.
Будь-яка, що використовується в програмі, процедура або функція повинна бути заздалегідь описаною в розділі описів.
Опис процедури має вигляд:
procedure ім'я(список формальних параметрів);
розділ описів
begin
оператори
end;
Опис функції має вигляд:
function ім'я(список
формальних параметрів): тип значення,
що повертається;
розділ
описів
begin
оператори
end;
Оператори підпрограми, облямовані операторними дужками begin/end, називаються тілом цієї підпрограми.
Список формальних параметрів разом з оточуючими дужками може бути відсутній. Він складається з однієї або декількох секцій, розділених символом ";". Кожна секція складається із списку змінних, перераховуваних через кому, після якого слідують двокрапка і тип. Кожна секція може передувати службовим словом var, що указує на те, що параметри передаються по посиланню (Параметри процедур і функцій).
Розділ описів процедури або функції влаштований так само, як і розділ описів основної програми. Тут описуються так звані локальні змінні і константи, типи а також вкладені процедури і функції. Всі такі локальні об'єкти доступні лише всередині даної підпрограми і не є видимими(доступними) ззовні.
Приклад опису процедури наводиться нижче:
procedure
Reverse(var
a: array
[1..100] of
integer; n: integer);
var
i,v: integer;
begin
for i:=1
to
n div
2 do
begin
v:=a[i];
a[i]:=a[n-i+1];
a[n-i+1]:=v;
end;
end;
Усередині тіла функції ім'я цієї функції можна використовувати як спеціальну змінну, якій необхідно привласнити значення, що повертається. Наприклад:
function
Add(a,b: real): real;
begin
Add:=a+b;
end;
Ім'я функції може бути використано з метою повернення значення тільки в лівій частині оператора присвоєння. Якщо ім'я функції зустрічається у виразі, то це трактується як рекурсивний виклик цієї функції.
Замість імені функції, усередині тіла функції можна використовувати іншу спеціальну змінну з ім'ям Result. На відміну від імені функції, змінну Result можна використовувати і у виразах:
function
MinElement(var
a: array
[1..100] of
real; n: integer): real;
var
i: integer;
begin
Result:=a[1];
for i:=1
to
n do
if
a[i]<Result then
Result:=a[i];
end;
Якщо усередині функції не присвоїти імені функції або змінної Result деяке значення, то функція поверне в результаті свого виклику непередбачуване значення.
Параметри,що вказуються при описі підпрограми, називаються формальними. Параметри, указувані при виклику підпрограми, називаються фактичними.
Якщо формальний параметр описаний із службовим словом var, то його називають параметром-змінною і говорять, що він передається по посиланню. Якщо ж параметр описаний без слова var, то його називають параметром-значенням і говорять, що він передається по значенню.
Якщо параметр передається по значенню, то при виклику підпрограми значення фактичних параметрів присвоюються відповідним формальним параметрам. Наприклад, хай є наступний опис процедури:
procedure
PrintSquare(i:
integer);
begin
writeln(i*i);
end;
Тоді при виклику PrintSquare(5*a-b) значення 5*a-b буде обчислено і привласнено змінній i, після чого виконається тіло процедури.
Якщо параметр передається по посиланню, то при виклику підпрограми фактичний параметр замінює собою в тілі процедури відповідний йому формальний параметр. У результаті будь-які зміни формального параметра-змінної усередині процедури приводять до відповідних змін фактичного параметра. Наприклад, якщо описана процедура
procedure
Mult2(var
a: integer);
begin
a:=a*2;
end;
то після виклику Mult(d) значення d збільшиться в 2 рази.
Як фактичний параметр-значення можна указувати будь-який вираз, тип якого співпадає з типом формального параметра або неявно до нього приводиться. Як фактичний параметр-змінної можна указувати тільки змінну, тип якої в точності співпадає з типом формального параметра.
При передачі параметра по посиланню в підпрограму передається адреса фактичного параметра. Тому якщо параметр займає багато пам'яті (масив, запис), то звичайно він також передається по посиланню. В результаті в процедуру передається не сам параметр, а його адреса, що економить пам'ять і час роботи. Наприклад:
procedure
Print(var
a: array
[1..10] of
integer; n: integer);
var
i: integer;
begin
for i:=1
to
n do
write(a[i],' ');
writeln;
end;
Параметр може бути також описаний із службовим словом const. Це означає, що він передається по значенню, але міняти його в підпрограмі заборонено. Наприклад:
procedure
PrintSquare1(i:
integer);
begin
i:=i*i; // правильно
writeln(i);
end;
procedure
PrintSquare2(const
i: integer);
begin
i:=i*i; // помилково!!!
writeln(i);
end;
Змінні, описані в розділі описів підпрограми, називаються її локальними змінними. Змінні ж, описані зовні підпрограми, називаються глобальними по відношенню до неї.
Параметри підпрограми вважаються її локальними змінними.
Якщо ім'я локальної змінної співпадає з ім'ям глобальної змінної, то локальна змінна приховує глобальну, так що до глобальної змінної не можна звернутися усередині підпрограми. Наприклад:
var i: real;
procedure p;
var i: integer;
begin
// до глобальної змінної i усередині процедури не можна звернутися
i:=5; // присвоєння локальної змінної i; ...
end;
В деяких ситуаціях виникає необхідність викликати підпрограму, описану далі в коді програми. Наприклад, ця необхідність виникає при непрямій рекурсії (підпрограма А викликає підпрограму B, а та у свою чергу викликає підпрограму А). В цьому випадку використовується випереджаюче оголошення підпрограми, що складається з її заголовка, за яким слідує службове слово forward. Наприклад:
procedure B(i: integer); forward;
procedure A(i: integer);
begin
...
B(i-1);
end;
procedure B(i: integer);
begin
...
A(i div 2);
end;
Forward-оголошення можливо тільки для зовнішніх підпрограм. Заборонено також робити forward-оголошення для вже описаної підпрограми.
В одному і тому ж розділі описів може бути визначено декілька процедур або функцій з одним ім'ям, але різною кількістю або типами параметрів. Імена таких процедур і функцій називаються перевантаженими, а їх створення - перевантаженням.
При виклику перевантаженої процедури або функції і вибирається та версія, у якої типи формальних параметрів співпадають з типами фактичних або найбільш близькі до них. Наприклад, якщо є опису
procedure p(b:
byte);
begin
end;
procedure
p(r:
real);
begin
end;
то при виклику p(1.0) буде вибрана переобтяжена версія з параметром типу real (точна відповідність), а при виклику p(1) буде вибрана переобтяжена версія з параметром типу byte (при цьому відбудеться перетворення фактичного параметра типу integer до типу byte).
Якщо жодна версія в поточному просторі імен не підходить до даного виклику, то генерується помилка компіляції "перевантажена процедура або функція з параметрами вказаних типів не знайдена". Якщо дві і більш версії в поточному просторі імен однаково добре підходять до даного виклику, то генерується помилка компіляції "неоднозначність при пошуку перевантаженої версії процедури або функції". Наприклад, якщо є опису
procedure p(i:
integer; r: real);
begin
end;
procedure
p(r: real; i:
integer);
begin
end;
то при виклику p(1,2) обидва вони однаково підходять, що приводить до неоднозначності.
Заборонено перенавантажувати процедуру функцією і функцію процедурою. Заборонено також перенавантажувати підпрограму іншою підпрограмою з тією ж кількістю і типами параметрів (var і не var-параметри одного типу вважаються рівними). Значення функції, що повертається, не бере участь в дозволі перевантаження, т.е перенавантажувані функції не можуть розрізнятися тільки типами значень, що повертаються.
Стандартні процедури і функції
|
Ім'я і параметри |
Процедура або функція |
Типи параметрів |
Тип значення, що повертається |
Дія |
|
Read(а,b...) |
процедура |
а,b,c - змінні простого типу або типу string |
|
вводить значення з клавіатури в змінні а, b ... |
|
Write(а,b...) |
процедура |
а,b,c - вирази простого типу, типа string або покажчики |
|
виводить значення а, b ... у вікно висновку
|
|
Readln(а,b...) |
процедура |
а,b,c - змінні простого типу або типу string |
|
вводить значення з клавіатури в змінні а, b ..., після чого пропускає всі символи, що залишилися, в поточному рядку введення. Якщо параметри процедури не вказані, то здійснює паузу у виконанні програми до натиснення клавіші Enter |
|
Writeln(а,b...) |
процедура |
а,b,c - вирази простого типу, типа string або покажчики |
|
виводить значення а, b ... у вікно висновку і здійснює перехід на наступний рядок. Якщо параметри процедури не вказані, то виконує тільки перехід на наступний рядок. |
|
Abs(x) |
функція |
x - integer, real, complex |
співпадає з типом параметра |
повертає абсолютне значення (модуль) x |
|
Sqr(x) |
функція |
x - integer, real, complex |
співпадає з типом параметра |
повертає квадрат x |
|
Sqrt(x) |
функція |
x - real, complex |
співпадає з типом параметра |
повертає квадратний корінь з x |
|
Sin(x) |
функція |
x - real, complex |
співпадає з типом параметра |
повертає синус x |
|
Cos(x) |
функція |
x - real, complex |
співпадає з типом параметра |
повертає косинус x |
|
Ln(x) |
функція |
x - real, complex |
співпадає з типом параметра |
повертає натуральний логарифм x |
|
Exp(x) |
функція |
x - real, complex |
співпадає з типом параметра |
повертає e в ступені x (e=2.718281...) |
|
Arctan(x) |
функція |
x - real, complex |
співпадає з типом параметра |
повертає арктангенс x |
|
Power(x,y) |
функція |
x, у - real |
real |
повертає x в ступені у |
|
Conj(z) |
функція |
z - complex |
complex |
повертає число, комплексно зв'язане до z |
|
Carg(z) |
функція |
z - complex |
real |
повертає аргумент комплексного числа z (в діапазоні (-Pi, Pi]) |
|
Round(x) |
функція |
x - real |
integer |
повертає результат округлення x до найближчого цілого |
|
Trunc(x) |
функція |
x - real |
integer |
повертає цілу частину х |
|
Int(x) |
функція |
x - real |
real |
повертає цілу частину х |
|
Frac(x) |
функція |
x - real |
real |
повертає дробову частину х |
|
Ord(x) |
функція |
x - порядкового типу |
integer |
повертає номер значення порядкового типу |
|
Chr(x) |
функція |
x - integer |
char |
повертає символ з кодом х |
|
Odd(x) |
функція |
x - integer |
boolean |
повертає True, якщо х - непарне, і False в осоружному випадку |
|
Inc(x) |
процедура |
x - порядкового типу |
|
Збільшує x на 1 |
|
Dec(x) |
процедура |
x - порядкового типу |
|
Зменшує x на 1 |
|
Inc(x,n) |
процедура |
x - порядкового типу, n - цілого типу |
|
Збільшує x на n |
|
Dec(x,n) |
процедура |
x - порядкового типу, n - цілого типу |
|
Зменшує x на n |
|
Pred(x) |
функція |
x - порядкового типу |
співпадає з типом параметра |
повертає попереднє значення порядкового типу |
|
Succ(x) |
функція |
x - порядкового типу |
співпадає з типом параметра |
повертає наступне значення порядкового типу |
|
Random(x) |
функція |
x - integer |
integer |
повертає випадкове ціле в діапазоні від 0 до x-1 |
|
Random |
функція |
|
real |
повертає випадкове речовинне в діапазоні [0..1) |
|
Include(s,x) |
процедура |
s - множина, x - елемент, тип якого сумісний з базовим типом множини |
|
включає елемент x в безліч s |
|
Exclude(s,x) |
процедура |
s - множина, x - елемент, тип якого сумісний з базовим типом множини |
|
виключає елемент x з безлічі s |
|
FillChar(v,count,x) |
процедура |
v
- змінна будь-якого типу, count - integer, |
|
заповнює count значеннями x область пам'яті, займану змінній v. Контроль виходу за межі не проводиться |
|
Ім'я і параметри |
Процедура або функція |
Типи параметрів |
Тип значення, що повертається |
Дія |
|
Length(s) |
функція |
s - string |
integer |
повертає довжину рядка s |
|
Сміттю(s,index,count) |
функція |
s - string, index і count - integer |
string |
повертає підрядок рядка s довжини count, починаючи з позицією index |
|
Delete(s,index,count) |
процедура |
s - string, index і count - integer |
|
видаляє в рядку s count символів починаючи з позицією index |
|
Insert(subs,s,index) |
процедура |
s, subs - string, index - integer |
|
вставляє підрядок subs в рядок s з позиції index |
|
Pos(subs,s) |
функція |
s, subs - string |
integer |
повертає позицію першого підрядка subs в рядку s (або 0 якщо підрядок не знайдений) |
|
SetLength(s,n) |
процедура |
s - string, n - integer |
|
встановлює довжину рядка s рівної n |
|
Str(x,s) |
процедура |
s - string, x - integer, real і n, m - integer |
|
перетворить x до рядкового уявлення (в другому і третьому випадках згідно формату висновку, встановлюваному n і m) і записує результат в рядок s |
|
Val(s,v,code) |
процедура |
s - string, v - integer, real, і code - integer |
|
перетворить рядок s до числового уявлення і записує результат в змінну v. Якщо перетворення можливо, то в змінній code повертається 0, якщо неможливо, то в code повертається ненульове значення |
|
IntToStr(i) |
функція |
i - integer |
string |
перетворить ціле число до рядка |
|
StrToInt(s) |
функція |
s - string |
integer |
перетворить рядок в ціле число . Якщо перетворення неможливе, то виникає помилка часу виконання |
|
FloatToStr(r) |
функція |
r - real |
string |
перетворить дійсне число до рядка |
|
StrToFloat(s) |
функція |
s - string |
real |
перетворить рядок в дійсне число. Якщо перетворення неможливе, то виникає помилка часу виконання |
|
UpCase(c) |
функція |
з - char |
char |
повертає символ з, перетворений до верхнього регістра
|
|
LowCase(c) |
функція |
з - char |
char |
повертає символ з, перетворений до нижнього регістра
|
|
UpperCase(s) |
функція |
s - string |
string |
повертає рядок s, перетворений до верхнього регістра
|
|
LowerCase(s) |
функція |
s - string |
string |
повертає рядок s, перетворений до нижнього регістра
|
Стандартні
процедури і функції для роботи з файлами
|
Ім'я і параметри |
Процедура або функція |
Типи параметрів |
Тип значення, що повертається |
Дія |
|
Assign(f,name) |
процедура |
f - змінна файлового типу, name - string |
|
зв'язує файлову змінну f з файлом з ім'ям name |
|
Reset(f) |
процедура |
f - змінна файлового типу |
|
відкриває файл, раніше пов'язаний з файловою змінною f за допомогою процедури Assign. Файл повинен існувати на диску, в осоружному випадку відбувається помилка часу виконання. Текстові файли відкриваються тільки на читання, файли, що типізуються, - на читання і запис |
|
Rewrite(f) |
процедура |
f - змінна файлового типу |
|
створює і відкриває новий файл, раніше пов'язаний з файловою змінною f за допомогою процедури Assign. Якщо файл з вказаним ім'ям вже існує, то він віддаляється, і замість нього створюється новий файл. Текстові файли відкриваються тільки на запис, файли, що типізуються, - на читання і запис |
|
Append(f) |
процедура |
f - змінна типу Text |
|
відкриває текстовий файл на запис для додавання. Файловий покажчик встановлюється в кінець файлу. |
|
Close(f) |
процедура |
f - змінна файлового типу |
|
закриває файл |
|
FileExists(name) |
функція |
name - string |
boolean |
повертає True, якщо на диску є файл з ім'ям name, в осоружному випадку повертає False |
|
CanCreateFile(name) |
функція |
name - string |
boolean |
повертає True, якщо можна створити файл з ім'ям name, в осоружному випадку повертає False |
|
Read(f,a,b...) |
процедура |
f - змінна файлового типу, а,b - змінні простого типу, типа string або покажчики |
|
прочитує значення з файлу f в змінні а, b ... Якщо файл типізується, то типи змінних а, b ... повинні співпадати з базовим типом файлу, а їх значення прочитуються з файлу в двійковому вигляді. Якщо файл текстовий, то змінні а, b ... можуть мати різні типи, а їх значення повинні зберігатися у файлі в текстовому вигляді |
|
Write(f,a,b...) |
процедура |
f - змінна файлового типу, а,b - вирази простого типу, типа string або покажчики |
|
записує значення а, b ... у файл f. Якщо файл типізується, то типи значень а, b ... повинні бути сумісними з базовим типом файлу. Якщо файл текстовий, то значення а, b ... виводяться в нього в текстовому вигляді, при цьому можуть бути використаний формати висновку
|
|
Readln(f,a,b...) |
процедура |
f - змінна типу Text, а,b - змінні простого типу, типа string або покажчики |
|
прочитує значення з текстового файлу f в змінні а, b ..., після чого пропускає символи до кінця рядка. Виклик readln(f) просто пропускає символи до кінця рядка |
|
Writeln(f,a,b...) |
процедура |
f - змінна типу Text, а,b - вирази простого типу, типа string або покажчики |
|
записує значення а, b ... в текстовий файл f, після чого записує в нього символ кінця рядка. Значення а, b ... записуються у файл в текстовому вигляді, при цьому можуть бути використаний формати висновку. Виклик writeln(f) просто записує у файл символ кінця рядка |
|
Eof(f) |
функція |
f - змінна файлового типу |
boolean |
повертає True, якщо файловий покажчик стоїть на кінці файлу, і False в осоружному випадку |
|
Eoln(f) |
функція |
f - змінна типу Text |
boolean |
повертає True, якщо файловий покажчик стоїть на кінці рядка, і False в осоружному випадку |
|
SeekEof(f) |
функція |
f - змінна типу Text |
boolean |
пропускає пропуски, символи табуляції і переходу на новий рядок, після чого повертає True, якщо файловий покажчик стоїть на кінці файлу, і False в осоружному випадку |
|
SeekEoln(f) |
функція |
f - змінна типу Text |
boolean |
пропускає пропуски, символи табуляції, після чого повертає True, якщо файловий покажчик стоїть на кінці рядка, і False в осоружному випадку |
|
FileSize(f) |
функція |
f - змінна типу file |
integer |
повертає кількість елементів у файлі, що типізується |
|
FilePos(f) |
функція |
f - змінна типу file |
integer |
повертає позицію файлового покажчика у файлі, що типізується (нумерація елементів у файлі, що типізується, починається з нуля) |
|
Seek(f,n) |
процедура |
f - змінна типу file |
|
переміщає файловий покажчик у файлі, що типізується, на n-тый елемент (нумерація починається з нуля) |
|
Truncate(f) |
процедура |
f - змінна типу file |
|
видаляє всі елементи файлу, що типізується, з поточної позиції файлового покажчика до кінця файлу |
|
Rename(f,name) |
процедура |
f - змінна файлового типу, name - string |
|
перейменовує файл, пов'язаний з файловою змінною f. Файл повинен бути закритий
|
|
Erase(f) |
процедура |
f - змінна файлового типу |
|
видаляє файл, пов'язаний з файловою змінною f. Файл повинен бути закритий
|
Стандартні процедури і функції для роботи з пам'яттю
|
Ім'я і параметри |
Процедура або функція |
Типи параметрів |
Дія |
|
New(p) |
процедура |
p - вказівник, що типізується |
виділяє динамічну пам'ять розміру, рівного розміру типа, на якого указує p, і повертає покажчик на неї в змінній p |
|
Dispose(p) |
процедура |
p - вказівник, що типізується |
звільняє динамічну пам'ять по покажчику p, раніше виділену процедурою New |
|
GetMem(p,n) |
процедура |
p - вказівник будь-якого типу, n - integer |
виділяє динамічну пам'ять розміру n байт і повертає покажчик на неї в змінній p |
|
FreeMem(p) |
процедура |
p - вказівник будь-якого типу |
звільняє динамічну пам'ять по покажчику p, раніше виділену процедурою GetMem |
|
Ім'я і параметри |
Процедура або функція |
Типи параметрів |
Тип значення, що повертається |
Дія |
|
Sleep(ms) |
процедура |
ms - integer |
|
Здійснює паузу у виконанні програми на ms мілісекунд |
|
Cls |
процедура |
|
|
Очищає вікно висновку
|
|
Halt(n) |
процедура |
n - integer |
|
Завершує програму. Виводить у вікно висновку попередження "Програма завершена викликом Halt(n)" |
Процедури та функції робои із графікою
Procedure arc(x, y,stAngle, endAngle, radius:integer);
Procedure arc(x, y,stAngle, endAngle, radius:integer; color:COLORS);
Procedure arc(x, y,stAngle, endAngle, radius, color:integer);
Procedure bar( x, y, x1, y1:integer);
Procedure bar(x, y, x1, y1, color : integer);
Procedure bar(x, y, x1, y1:integer; color:COLORS);
Procedure bar3d(x, y, x1, y1, z:integer; top:boolean);
Procedure circle(x, y, radius:integer);
Procedure circle(x, y, radius :integer; color :COLORS);
Procedure circle(x, y, radius, color :integer);
Procedure close();
Procedure cleardevice();
Procedure closegraph();
Procedure ellipse(x, y, rWidth, rHeight:integer);
Procedure ellipse(x, y, rWidth, rHeight:integer; color:integer);
Procedure ellipse(x, y, rWidth, rHeight:integer; color:COLORS);
Procedure fillellipse(x, y, rWidth, rHeight:integer);
Procedure fillellipse(x, y, rWidth, rHeight, color:integer);
Procedure fillellipse(x, y, rWidth, rHeight:integer; color:COLORS);
Function getmaxx():integer;
Function getmaxy():integer;
Procedure image(x, y :integer; path:string);
Procedure initgraph();
Procedure initgraph(setWidth, setHeight:integer);
Procedure initgraph(drv, drm:integer; text:string);
Procedure line(x, y, x1, y1:integer);
Procedure line(x, y, x1, y1:integer; color :COLORS);
Procedure line(x, y, x1, y1:integer; color :integer);
Procedure lineto(x, y:integer);
Procedure lineto(x, y, color:integer);
Procedure lineto(x, y:integer; color:COLORS);
Procedure moveto(x, y:integer);
Procedure outtext(text:string);
Procedure outtext(text:string; color:integer);
Procedure outtext(text:string; color:COLORS);
Procedure outtextxy(x, y:integer; text:string);
Procedure outtextxy(x, y:integer; text:string; color:integer);
Procedure outtextxy(x, y:integer; text:string; color:COLORS);
Procedure pieslice(x, y, stAngle, endAngle, radius:integer);
Procedure pieslice(x, y, stAngle, endAngle, radius, color:integer);
Procedure pieslice(x, y, stAngle, endAngle, radius:integer; color:COLORS);
Procedure putpixel(x, y:integer);
Procedure putpixel(x, y:integer; color:COLORS);
Procedure putpixel(x, y:integer; color:integer);
Procedure rectangle(x, y, x1, y1 :integer);
Procedure rectangle(x, y, x1, y1 :integer; color :COLORS);
Procedure rectangle(x, y, x1, y1 :integer; color :integer);
Procedure save(path: string);
Procedure setbkcolor(color:COLORS);
Procedure setbkcolor(color:integer);
Procedure setcolor(color:COLORS);
Procedure setcolor(color:integer);
Procedure setfillcolor(color:COLORS);
Procedure setfillcolor(color:integer);
Procedure setfillstyle(patern:PATERN; color:COLORS);
Procedure setfillstyle(patern:integer; color:COLORS);
Procedure setfillstyle(patern:PATERN; color:integer);
Procedure setfillstyle(patern:integer; color:integer);
Procedure setlinestyle(style:LINESTYLE; upattern, thickness:integer);
Procedure setlinestyle(style, upattern, thickness:integer);
Procedure settextstyle(font:string; mydirection:DIRECTION; size:integer);
Procedure settextstyle(font:string; mydirection, size:integer);
Клас є складовим типом, що складається з полів (змінних), методів (процедур і функцій) і властивостей.
Опис класу має вигляд:
type
ім'я
класу=class
опису полів
оголошення або опису методів і опису властивостей
end;
Після слова class в дужках може бути вказано ім'я класу-предка (див. п. Наслідування).
Поля описуються за тими ж правилами, що і поля в записах (див. п. Записи). Поля і методи утворюють інтерфейс класу.
На відміну від Borland Delphi, тіла процедур і функцій, що є методами, можуть описуватися як всередині, так і зовні класу. Опис методів ідентично опису звичайних процедур і функцій. Оголошення методу є заголовком процедури або функції, яка повинна бути описаний пізніше або всередині, або зовні тіла класу. При описі зовні класу ім'я методу повинне передувати ім'ям класу з подальшою крапкою.
Наприклад:
type
Student=class
name: string;
course, group: integer;
constructor
Create(nm: string;
c,gr: integer);
procedure
Print;
begin
writeln('Имя:',name,'
курс:',course,' группа:');
end;
procedure
NextCourse;
begin
Inc(course);
end;
end;
constructor
Student.Create(nm: string;
c,gr: integer);
begin
name:=nm;
course:=c;
group:=g;
end;
Тут конструктор Create оголошений в класі, а визначений зовні класу, а методи Print і NextCourse визначені усередині класу. При визначенні методу зовні класу його імені передує ім'я класу з подальшою крапкою.
Звичайно тільки невеликі методи визначаються усередині класу. Це робиться для того, щоб інтерфейс класу був осяжним.
Оголошення методу не може слідувати за визначенням цього ж методу.
Екземпляри класів називаються об'єктами. Кожний об'єкт містить копії всіх полів, визначених в його класі, і може користуватися всіма його методами. Змінна типу клас зберігає насправді вказівник на об'єкт. Проте, при зверненні до полів, методам або властивостям об'єкту розіменування такого вказівника не потрібне; указується ім'я об'єкту і потім, після роздільника-крапки, указується ім'я поля, методу або властивості:
var s:
Student;...s.name:='Иванов';
s.course:=1; s.group:=3;s.Print;s.GotoNextCourse;s.Print;
Як і інші вказівники, змінна типу клас може містити значення nil:
s:=nil;
...
if
s=nil
then ...
Декількох змінних типу клас можуть посилатися на один об'єкт:
var s1,s2:
Student;...s1.name:='
Петров';s2:=s1;writeln(s2.name);
// s2.name='Петров'
Локальні визначення класів (тобто визначення в процедурах і функціях) заборонені.
В методах, описаних усередині класу заборонені вкладені описи процедур.
Конструктори
і деструктори
Об'єкти створюються і знищуються за допомогою спеціальних методів, званих конструкторами і деструкторами.
Конструктор є функцією, що створює об'єкт в динамічній пам'яті, що ініціалізовує його поля і повертає вказівник на створений об'єкт. Цей вказівник звичайно відразу присвоюється змінній типу клас. При описі конструктора замість службового слова function використовується службове слово constructor. Крім того, для конструктора не вказується тип значення, що повертається. Для виклику конструктора слід вказати ім'я класу, за яким слідує крапка-роздільник, ім'я конструктора і список параметрів. Наприклад:
var s:
Student;...s:=Student.Create('Иванов',1,3);
При створенні об'єкту поля не ініціалізувалися автоматично, тому рекомендується всі поля ініціалізувати в конструкторі явно.
Деструктор є процедурою, що знищує об'єкт, звільняючу динамічну пам'ять, яку цей об'єкт займав. При описі деструктора замість службового слова procedure використовується службове слово destructor. Деструктор об'єкту викликається як звичайний метод:
s.Destroy;
Після виклику деструктора користуватися об'єктом (тобто звертатися до його полів і викликати його методи) не можна. Щоб це підкреслити, корисно відразу після виклику деструктора присвоїти змінній, що представляє об'єкт, значення nil:
s:=nil;
В Borland Delphi, прийнято використовувати ім'я Create для конструктора і ім'я Destroy - для деструкції.
Властивості дозволяють здійснювати доступ до полів класу, попутно виконуючи деякі дії. Властивість описується в класі таким чином:
property <Prop>: тип read <ім'я функції читання> write <ім'я процедури запису>;
Як правило, кожна властивість пов'язана з деяким полем класу і повертає значення цього поля за допомогою функції читання, а міняє - за допомогою процедури запису. Функція читання і процедура запису повинна бути методами цього класу і мати наступний вигляд:
function getProp:
тип;
procedure
setProp(v:
тип);
Секція write може бути опущений, тоді доступ до поля через властивість можна здійснювати тільки на читання (властивості тільки для читання).
Наприклад, розглянемо тип Person (персона), що має поле _age (вік). Доступ до поля _age здійснюватимемо через властивість Age:
type Person=class
_age: integer;
procedure
setAge(a:
integer);
begin
if
a>0 then
_age:=a
else
writeln('Помилка
в Person.setAge: вік не може бути від’ємним');
end;
function
getAge: integer;
begin
writeln('Здійснено
доступ до поля _age на зчитування');
Result:=_age;
end;
property
Age: integer read
getAge write
setAge;end;var
p: Person;
a:
integer;...p:=Person.Create;p.Age:=-3;
// помилка!!!i:=p.Age;
// зчитування поля _age
Кожного разу, коли ми присвоюємо властивості Age нове значення, викликається процедура setAge з відповідним параметром. Всякий раз, коли ми прочитуємо значення властивості Age, викликається функція getAge.
З прикладу видно, що властивості поводяться аналогічно полям. При цьому вони можуть проводити додаткові дії, наприклад, перевірку на допустимість присвоюваного значення. Доступ же до полів класів напряму зв'язаний з помилками:
p._age:=-3;
Присвоєння полю _age негативного значення помилково, але подібна помилка не буде оброблена.
Замість імені функції читання або імені процедури запису можна використовувати ім'я поля, наприклад:
property Age: integer read _age write setAge;
В цьому випадку рядок i:=p.Age еквівалентна рядку i:=p._age.
Звичайно для доступу до поля на читання в секції read властивості указується саме поле, оскільки звичайно при читанні поля ніяких додаткових дій проводити не вимагається.
Властивості не можуть передаватися по посиланню в процедури і функції. Наприклад, наступний код помилковий:
Inc(p.Age); // помилка!
Якщо вимагається обробити значення властивості, передавши його по посиланню, то треба скористатися допоміжною змінною:
a:=p.Age;Inc(a);p.Age:=a;
Властивості дуже зручні при роботі з візуальними об'єктами, оскільки дозволяють автоматично перемальовувати об'єкт, якщо змінити які-небудь його візуальні характеристики. Наприклад, якщо створена кнопка b1 типу Button, то для візуальної зміни її ширини достатньо присвоїти значення її властивості Width:
b1.Width:=100;
Процедура для запису цієї властивості в приватне поле _width виглядатиме приблизно так:
procedure
SetWidth(w: integer);begin
if
(w>0) and
(w<>_width)
then
begin
_width:=w;
<перемалювання
кнопки>
endend;
Слід звернути увагу на другу частину умови в операторі if: w<>_width. Додавання цієї перевірки дозволяє уникнути зайвого перемальовування кнопки у випадку, якщо її ширина не міняється.
Індексні властивості поводяться аналогічно полям-масивам і використовуються, як правило, для доступу до елементів контейнерів. Як і при використовуванні звичайних властивостей, при використовуванні індексних властивостей можуть попутно виконуватися деякі дії.
Індексна властивість описується в класі таким чином:
property Prop[ім'я: тип індексу]: тип read ім'я функції читання write ім'я процедури запису;
Функція читання і процедура запису повинна бути методами цього класу і мати наступний вигляд:
function getProp(ind:
тип індексу): тип;
procedure
setProp(ind:
тип індексу; v: тип);
Кожного разу, коли ми виконуємо присвоєння Prop[ind]:=value, викликається процедура setProp(ind,value), а коли прочитуємо значення Prop[ind], викликається функція getProp(ind).
Перша індексна властивість, описана в класі, називається індексною властивістю по замовчуванню і дозволяє користуватися об'єктами класу як масивами, тобто використовувати запис а[i], де а - об'єкт класу.
Принципова відмінність індексних властивостей від полів-масивів полягає в тому, що тип індексу може бути довільним (зокрема, рядковим). Це дозволяє легко реалізувати так звані асоціативні масиви, елементи яких індексуються рядками. Наведемо приклад реалізації класу AssocArray. Цей клас можна використовувати, наприклад, для підрахунку кількості появ кожного слова в тексті:
type
AssocArray=class
private
words: StringArray; // слова
nums: IntArray; // к-сть
появ слов
public
constructor
Create;
begin
words:=StringArray.Create;
nums:=IntArray.Create;
end;
procedure
setProp(ind: string;
value: integer);
function
getProp(ind: string):
integer;
property
Items[ind: string]:
integer read
getProp write
setProp;
property
Keys: StringArray read
words;
property
Values: IntArray read
nums;
end;
procedure
AssocArray.setProp(ind: string;
value: integer);
var
i: integer;
begin
i:=words.IndexOf(ind); // пошук
слова
if
i<>0 then
// якщо
знайдено, то
nums[i]:=value
// встановлення к-сті появ слова
else
// якщо
не знайдено, то
begin
words.add(ind);
// добавлення слова в массив слов
nums.add(value);
// установка к-сті появ слова
end;
end;
function
AssocArray.getProp(ind:
string):
integer;
var
i: integer;
begin
i:=words.IndexOf(ind); //
пошук слова
if
i<>0
then
// якщо
знайдено, то
Result:=nums[i]
// повернення к-сті появ слова
else
// якщо
не знайдено, то
begin
words.add(ind);
// добавлення слова в массив слов
nums.add(0);
// установка к-сті появ слова рівними
нулю
Result:=0;
end;
end;
var
CountNames:
AssocArray;
...
CountNames.Items['крокодил']:=3;
CountNames['бегемот']:=5;
// індексна властивість по
замовчуванню
CountNames['бегемот']:=CountNames['бегемот']+2;
Як і звичайні властивості, індексні властивості не можуть передаватися по посиланню в процедури і функції. Так, в останньому прикладі не можна написати
Inc(CountNames['бегемот'],2);
Усередині кожного методу неявно визначається змінна Self, що посилається на об'єкт, цей метод, що викликав. Наприклад:
type
A=class
i: integer;
constructor
Create(i:
integer);
begin
Self.i:=i;
end;
end;
У момент виклику конструктора Create об'єкт буде вже створений. Конструкція Self.i посилається на поле i цього об'єкту, а не на параметр i функції Create.
Клас може бути успадковуваний від іншого класу. Наприклад, при оголошенні
type
MyClass=class(BaseClass)...end;
клас MyClass успадковується від класу BaseClass.
Клас-нащадок називається також похідним класом або підкласом, а клас-предок - базовим класом або надклассом. Нащадок автоматично успадковує всі поля і методи свого предка. Він може також визначати нові поля і методи, а також перевизначати (заміщати) методи предка.
Імена полів і методів, оголошені в класі, доступні до кінця оголошення класу, а також у всіх його нащадках.
Всі класи неявно успадковуються від класу Object. Цей клас оголошений таким чином:
type Object=class
constructor
Create;
destructor
Destroy;
function
TypeName: string;
function
ToString: string;
end;
Таким чином, будь-який клас може створювати свої об'єкти, викликаючи конструктор Create без параметрів, і знищувати їх, викликаючи деструктор Destroy, навіть якщо ці методи не приведені в його описі:
var m:
MyClass;...m:=MyClass.Create;...m.Destroy;
В кінці роботи програми всі створені об'єкти повинні бути зруйнований. Тому для кожного створеного об'єкту рекомендується явно викликати деструктор.
Метод TypeName повертає ім'я класу об'єкту, а метод ToString - рядкове представлення об'єкту. В класі Object метод ToString також повертає ім'я класу об'єкту, але ця поведінка може бути перевизначений в нащадках. Наприклад:
type MyClass=class
i: integer;
constructor
Create(i:
integer);
begin
Self.i:=i;
end;
function
ToString:
string;
begin
Result:=IntToStr(i);
end;
end;var
a:
MyClass;...a:=MyClass.Create(3);writeln(a.TypeName);
// MyClasswriteln(a.ToString);
// 3
Кожне поле, метод або властивість класу має атрибут, званий видимістю. В Pascal існують три типи атрибутів видимості: public (відкритий), private (закритий) і protected (захищений). До члена класу, що має атрибут public, можна звернутися з будь-якого місця програми, члени класу з атрибутом private доступні тільки усередині методів цього класу, члени класу з атрибутом protected доступні усередині методів цього класу і всіх його підкласів. Атрибути видимості можуть знаходитися усередині класу, при цьому всі подальші члени придбавають цей атрибут. Наприклад:
type
A=class
private
x: integer;
protected
a: integer;
public
constructor Create(xx:
integer);
begin
x:=xx; // вірно,
оскільки ми усередині методу класу,
якому належить закрите поле
a:=0; // вірно
end;
procedure
print;
end;
B=class(A)
procedure
print;
begin
writeln(a); // вірно,
оскільки а - захищене поле
writeln(x); // невірно,
оскільки
х -
закрите поле
end;
end;
...
var
a1: A;
...
writeln(a1.x); // невірно,
оскільки х - закрите поле
writeln(a1.a);
// невірно,
оскільки а - захищене поле
a1.print;
// вірно,
оскільки print - відкритий метод
За умовчанням всі члени є відкритими. Зокрема, метод print класу B - відкритий.
Якщо x - закритий або захищений член класу, то доступ до нього з використанням явної вказівки об'єкту неможливий: запис a.x викличе помилку при компіляції "поле x недоступне". Виключення складає запис Self.x, що використовується в методі класу, містить x.
Метод базового класу може бути перевизначений (заміщений) в підкласах. Якщо при цьому вимагається викликати метод базового класу, то використовується службове слово inherited (англ.- успадковуваний). Наприклад:
type
Person=class
name: string;
age: integer;
constructor
Create(nm: string;
ag: integer);
begin
name:=nm;
age:=ag;
end;
procedure
Print;
begin
writeln('Ім’я:
',name,' Вік: ',age);
end;
end;
Student=class(Person)
course, group:
integer;
constructor
Create(nm: string;
ag,c,gr: integer);
begin
inherited
Create(nm,ag);
course:=c;
group:=gr;
name:=nm;
age:=ag;
end;
procedure
Print;
begin
inherited
Print;
writeln('Курс:
',course,' Група: ',group);
end;
end;
Тут метод Print похідного класу Student викликає спочатку метод Print, успадковуваний від базового класу Person, за допомогою конструкції inherited Print. Аналогічно конструктор Create класу Student викликає спочатку конструктор Create базового класу Person, також використовуючи службове слово inherited. Слід звернути увагу, що конструктор базового класу викликається в цьому випадку як процедура, а не як функція, при цьому створення нового об'єкту не відбувається.
Об'єкт похідного класу неявно приводиться до типу базового класу. Наприклад, якщо у нас є клас
type MyClass=class
procedure
print; end;
то можна ініціалізувати змінну класу Object об'єктом класу MyClass:
var o:
Object;...o:=MyClass.Create;
Тепер в змінній типу Object зберігається адреса об'єкту MyClass. Це можна перевірити, викликавши функцію TypeName класу Object:
writeln(о.TypeName); // буде виведений 'MyClass'
Тип класової змінної, оголошений при описі, прийнято називати її статичним типом, а тип об'єкту, на який посилається класова змінна в процесі виконання програми - її динамічним типом. Динамічний тип може або співпадати із статичним, або бути його спадкоємцем. Об'ект базового класу можна явно перетворити до типу похідного класу. Так, в приведеному вище прикладі, хоча змінна о посилається на об'єкт типу MyClass, користується методом print, визначеним в класі MyClass, через змінну о не можна. Щоб це здійснити, об'єкт базового класу повинен бути явно приведений до об'єкту похідного класу:
var m:
MyClass;...m=MyClass(o);
Після цього, зрозуміло, можна викликати будь-які методи похідного класу і звертатися до його полів:
m.print;
При виконанні цього перетворення необхідно, щоб в змінній о знаходився саме об'єкт класу MyClass або будь-якого похідного від нього класу. В протилежному випадку відбудеться помилка при виконанні програми.
Операція is призначена для перевірки того, чи має класова змінна вказаний динамический тип. Операція as дозволяє безпечно перетворити змінну одного класового типу до іншого класового типу (у відмінність від явного приведения классового типа).
Якщо a1 - змінна класового типу, а B - тип класу, то вираз a1 is B повертає True якщо змінна a1 має динамічний тип, співпадаючий з B або є одним з його нащадків, і False в протилежному випадку. Наприклад:
type
A=class
end;
B=class(A)
end;var
a1:
A;...a1:=B.Create;writeln(a1
is
B); // True
Якщо a1 - змінна класового типу, а B - тип класу, то вираз a1 as B повертає об'єкт класу B, a1 має динамічний тип B або похідний від нього і nil в протилежному випадку. Наприклад:
var b1:
B;...b1:=a1
as
B;
Фактично останній рядок робить те ж, що і наступний фрагмент коду:
Хай перевизначений в підкласі метод базового класу має той же список формальних параметрів (а для функцій - і тип значення, що повертається). Наприклад:
type
Base=class
procedure
Print;
begin
writeln('Base');
end;
end;
Derived=class(Base)
procedure
Print;
begin
writeln('Derived');
end;
end;
Розглянемо різні способи виклику методу Print:
var
b,b1: Base;
d: Student;
...
b:=Base.Create;
d:=Derived.Create;
b1:=d;
b.Print; //
викликається Base.Print
d.Print; //
викликається Derived.Print
b1.Print;
Яка версія методу Print викликається в останньому випадку - класу Base або класу Derived? В об'єктно-орієнтованих мовах програмування можливі дві ситуації. Якщо рішення про те, який метод викликати, ухвалюється на етапі компіляції на підставі типу, заявленого при описі b1, то викликається метод Base.Print (говорять також, що має місце раннє скріплення імені методу з його тілом). Якщо ж рішення про те, який метод викликати, ухвалюється на етапі виконання програми залежно від реального типу об'єкту, на який посилається змінна b1, то викликається метод Derived.Print (говорять також, що має місце пізнє скріплення). Методи, для яких реалізується пізнє скріплення, називаються віртуальними, а здатність об'єкту викликати через змінну базового класу метод похідного класу на підставі інформації під час виконання програми називається поліморфізмом.
Поліморфізм (англ.: багато форм) використовується за ситуації, коли для групи взаємозв'язаних об'єктів вимагається виконати єдину дію, але кожний з цих об'єктів повинен виконати вказану дію по-своєму (тобто у дії виникає багато форм). Для цього визначається базовий для всіх об'єктів клас з методом, передбаченим для виконання вказаної дії, після чого цей метод перевизначається у всіх нащадках.
Наприклад:
type
Shape=class
procedure
Draw; begin
end;
end;
Point=class
procedure
Draw; begin
... end;
end;
Rectangle=class
procedure
Draw; begin
... end;
end;
Circle=class
procedure
Draw; begin
... end;
end;var
a: array[1..4]
of
Shape;...
a[1]:=Point.Create;
a[2]:=Rectangle.Create;
a[3]:=Point.Create;
a[4]:=Circle.Create;
for
i:=1 to
4 do
a[i].Draw;
В даному випадку як єдина дія виступає метод Draw, але кожний об'єкт виконує його по-своєму, забезпечуючи поліморфну поведінку. Говорять, що методи Draw в базовому класі Shape і його нащадках утворюють ланцюжок віртуальності.
Увага! Якщо перевизначається private-метод, то ланцюжок віртуальності ламається, тобто метод розглядається як перший з цим ім'ям в новому ланцюжку віртуальності.
Модулі
Модулі призначені для розбиття тексту програми на декілька файлів. В модулях описуються змінні, константи, типи, класи, процедури і функції. Для того, щоб ці об'єкти можна було використовувати в зухвалому модулі (якою може бути і основна програма), слід вказати ім'я файлу модуля (без розширення .pas) в розділі uses зухвалого модуля. Файл модуля повинен знаходитися або в тому ж каталозі, що і основна програма, або в підкаталозі Units системного каталога програми Pascal.
Модуль є файлом з наступною структурою:
unit ім'я модуля;
Interface
[Usese]розділ
підключення модулів
розділ глобальних
описів змінних,розділ заголовків
процедур і функцій
Implementation
[Uses]розділ
підключення модулів
розділ локальних
описів змінних,розділ реалізації
процедур і функцій
begin
розділ
ініціалізації
розділ фіналізації
end.
Перший рядок обов'язковий і називається заголовком модуля.
Розділ підключення модулів починається із службового слова uses, за яким слідує список імен модулів, перераховуваних через кому.
Розділ описів може включати розділи опису змінних, констант, типів, процедур і функцій, які слідують один за одним в довільному порядку.
Розділ ініціалізації складається із службового слова initialization, після якого слідують оператори, що розділяються символом "крапка з комою". Оператори з розділу ініціалізації модуля виконуються до початку основної програми.
Розділ фіналізації складається із службового слова finalization, після якого слідують оператори, що розділяються символом "крапка з комою". Оператори з розділу фіналізації модуля виконуються після закінчення основної програми.
Розділ фіналізації може бути відсутній, або обидва розділи ініціалізації і фіналізації можуть бути відсутній. Розділ ініціалізації може також починатися із службового слова begin, в цьому випадку розділ финализации відсутній.
Наприклад:
unit
Lib;
uses
GraphABC;
const
Dim=5;
var
Colors: array
[1..Dim] of
integer;
function
RandomColor: integer;
begin
Result:=RGB(Random(255),Random(255),Random(255));
end;
procedure
FillByRandomColor;
var
i: integer;
begin
for i:=1
to
Dim do
Colors[i]:=RandomColor;
end;
initialization
FillByRandomColor;
end.