Показує секунду з лідируючим нулем (00 - 59) Показує час у форматі гг: мм
Показує час у форматі гг: мм: сс
Показує час у 12-годинному форматі (am - до полудня, pm - після полудня)
Показує час у 12-годинному форматі без покажчика до / після полудня
Використовує Windows-роздільник дати.
Використовує Windows-роздільник часу
. Procedure Abort;
Використовується в контексті з іншим оператором; скасовує "заднім числом" оператор в разі його аварійного завершення, блокує видачу повідомлення про помилку, зручний для використання в блоці try ... finally.
13. Структурні оператори
До їх числа належать:
складений оператор,
умовний оператор If,
оператор варіанту Case,
оператор циклу For - Do,
оператор циклу While - Do,
оператор циклу Repeat - Until,
оператор запису With,
оператор Try - Except - End,
оператор Try - Finally - End,
оператор On - Do,
оператор Try - Finally - End.
13.1. Складовою оператор
Це проста структура наступних один за одним операторів, укладених в операторні дужки begin ... end.
Синтаксис складеного оператора:
Begin
Оператор1
Оператор2
...
ОператорN
End;
Складовою оператор застосовується в тих випадках, коли будь-яку дію необхідно застосувати не до одного, а відразу до кількох операторам.
Приклад:
Begin
R: = X;
X: = Y;
Y: = R;
End;
13.2. Умовний оператор If
Синтаксис допускає два види оператора:
if логічне вираз then оператор1 else оператор2;
і його усічений варіант:
if логічне вираз then оператор1;
Оператор працює наступним чином. Спочатку обчислюється логічес-кое вираз. Якщо воно істинне, то виконується оператор1, інакше - оператор2. Усічений оператор виконує оператор1 тільки у випадку справжнього значення логічного виразу і не робить ніяких дій у разі його хибність.
Приклади:
if (x <10.7) then a [4]: = 5 else a [4]: = 6;
if (x <10.7) then a [4]: = 5;
Допустима вкладеність умовних операторів усередині складеного умовного оператора. Наприклад, оператору
if L1 then if L2 then St1 else St2 else St3;
еквівалентний оператор
if L1 then
begin
if L2 then St1 else St2;
end
else St3;
У цьому операторі для підвищення структурованості використані операторні дужки begin ... end. При конструюванні складного умовного оператора щоб уникнути логічних помилок слід віддавати перевагу структурному способом запису такого оператора.
13.3. Оператор варіанту Case
Синтаксис оператора:
Case Selector of
Const1: Оператор1;
Const2: Оператор2;
...
ConstN: ОператорN
[Else Оператор];
End;
Selector може бути будь-який простий тип крім Real. Кожна з Const1 ... ConstN може бути значення, декілька перерахованих через кому значень або відрізок типу. Оператор Else, як видно з опису, може бути відсутнім. У тому випадку, якщо він присутній, то діє загальне правило: перед словом Else не повинно бути символу ";" (крапка з комою). Пояснимо роботу оператора Case на прикладі:
Case i of
0: x: = 0;
1,3: x: = 1;
10 .. 15: x: = 2
else x: = 3;
End;
При виконанні оператора Case управління буде передано того оператору, який відмічено константою, що є значенням змінної i. Наприклад, якщо до моменту виконання Case-оператора i = 0, то буде виконаний оператор x: = 0. Інакше, якщо i = 1 або i = 3, то буде виконаний оператор x: = 1; інакше, якщо значення i в діапазоні 10 .. 15, то буде виконаний оператор x: = 2; нарешті, якщо i не дорівнює жодної з перерахованих вище констант, то буде виконаний оператор x: = 3, наступний за словом else (інакше).
13.4. Оператор циклу For - Do
Синтаксис оператора має два різновиди:
For лічильник циклу: = нач.знач. To конеч.знач. Do оператор
For лічильник циклу: = нач.знач. Downto конеч.знач. Do оператор
Тут конструкція For .. Do називається заголовком циклу, оператор - тілом циклу.
Для циклів мають дотримуватися такі правила і обмеження:
початкове і кінцеве значення лічильника циклу повинні бути однакових простих типів, крім Real;
в тілі циклу лічильник не повинен міняти значення;
вхід в цикл минаючи заголовок заборонено;
для першого різновиду початкове значення не повинно бути більше кінцевого;
для другого різновиду початкове значення не повинно бути менше кінцевого.
Перший різновид оператора циклу For працює наступним чином. Спочатку лічильник циклу приймає нач.знач. і виконується оператор, розташований слідом за словом Do. Потім значення лічильника буде збільшено на крок лічильника 1 і знову буде виконаний оператор і т. д., поки лічильник не перебере всі значення від нач.знач. до конеч.знач.
Приклад.
s: = 0;
For i: = 1 to 44 do s: = s + z [i];
У результаті в змінної s буде накопичена сума перших 44 елементів масиву z.
Інший різновид оператора For відрізняється лише негативним кроком -1 лічильника.
Приклад.
s: = 0;
For i: = 44 Downto 1 do s: = s + z [i];
Буде отриманий той же результат.
13.5. Оператор циклу While - Do
Синтаксис оператора:
While логічне вираження Do оператор;
Цикл виконує оператор, розташований слідом за словом Do до тих пір, поки істинно логічне вираження, розташоване за словом While ("виконуй, поки істинно").
Приклад.
x: = 0;
i: = 0;
While (x <101.667) do
Begin
Inc (i);
X: = X + 5.617;
Y [i]: = Func (i + 6, 9 * i, X);
End;
У цьому прикладі цикл буде виконуватись до тих пір, поки не виконається умова x <101.667. У тілі циклу змінна X з кожним кроком циклу збільшує своє значення на 5.617 так, що на певному етапі умова x <101.667 вперше не буде виконано. У цей момент без входу в тіло цикл закінчить роботу.
13.6. Оператор циклу Repeat - Until
Синтаксис оператора:
Repeat
Оператор1;
Оператор2;
...
ОператорN;
Until логічне вираження;
Цикл працює, поки логічне вираження помилково ("повторюй, поки не виконається").
Приклад.
s: = 0;
i: = 0;
Repeat
Inc (i);
s: = s + z [i];
Until (i = 44);
У цьому прикладі цикл буде виконуватись до тих пір, поки не виконається умова i = 44. Результат буде той же, що у прикладі для For-циклу.
13.7. Оператори Break і Continue
Оператор Break може бути розміщений у тілі циклу. При його виконанні цикл припиняє роботу і вважається виконаним.
Приклад.
s: = 0;
i: = 0;
Repeat
Inc (i);
s: = s + z [i];
if (s> 14) then Break;
Until (i = 44);
У цьому прикладі цикл буде виконуватись до тих пір, поки не виконається умова i = 44 або якщо в операторі if мінлива s перевищить значення 14.
Оператор Continue також може бути розміщений у тілі циклу. При його виконанні керування незалежно від того, де він розташований, відразу передається в початок циклу для виконання наступного кроку.
Приклад.
s: = 0;
i: = 0;
Repeat
Inc (i);
s: = s + z [i];
if (s> 20) then Continue;
if (s> 14) then Break;
Until (i = 44);
У цьому прикладі якщо в першому операторі if виконається умова s> 20, то спрацює оператор Continue. Він відразу передасть управління на перший оператор у тілі циклу - Inc (i), запобігши тим самим виконання нижче-наступних операторів - другого if і Until.
13.8. Вкладені цикли
У тілі оператора циклу можуть бути розміщені інші оператори циклу. Такі структури називаються вкладеними циклами. Мова допускає будь-яку глибину вкладеності циклів. При використанні вкладених циклів необхідно мати на увазі наступне:
всі вкладені цикли For - Do повинні мати різні лічильники (інакше це суперечило б вимогу на заборону зміни значення лічильника всередині циклу);
немає ніяких обмежень на достроковий вихід із внутрішньої циклу назовні;
неприпустимий вхід у внутрішній цикл For - Do, минаючи його заголовок, що відповідає загальному вимогу про коректне вході в цикл.
Вкладені цикли використовуються в ситуаціях, коли на кожному кроці зовнішнього циклу необхідно повністю виконати внутрішній цикл.
Приклад.
Const
n = 15;
m = 24;
Var
i, j: Byte;
R, Tau, s: Real;
z: array [1 .. n, 1 .. m] of Real;
...
{Заповнення масиву z з використанням вкладених циклів}
Tau: = Pi / m;
For i: = 1 to n do begin
R: = 4.0 * Pi * Sin (i * Tau); {перший оператор у тілі циклу по i}
For j: = 1 to m do z [i, j]: = R + j; {другий оператор у тілі циклу по i}
end {i};
{Обчислення суми позитивних елементів масиву z з використанням вкладених циклів}
s: = 0;
For i: = 1 to n do
For j: = 1 to m do
if (z [i, j]> 0) then s: = s + z [i, j];
Наведений приклад містить дві структури вкладених циклів. Перша структура призначена для заповнення елементів двовимірного масиву z за допомогою математичної формули
Зовнішній цикл з лічильником i в тілі циклу містить два оператори - оператор присвоювання (обчислення значення допоміжної змінної R з метою скорочення часу обчислень) і оператор внутрішнього циклу з лічильником j. Оскільки зовнішній цикл у своєму тілі містить кілька операторів, то вони укладені в операторні дужки begin ... end.
Ця структура працює наступним чином. Після входу в зовнішній цикл мінлива i (лічильник цього циклу) прийме значення 1. Далі буде обчислено значення змінної R при i = 1. Після цього буде виконаний внутрішній цикл з лічильником j, де j на кожному кроці буде послідовно приймати значення 1, 2, 3, ... m (i при цьому залишається незмінним і рівним 1). У результаті будуть обчислені елементи z11, z12, ..., z1m першого рядка масиву. Потім буде виконаний повернення до заголовка зовнішнього циклу, де значення лічильника i буде збільшено на 1 (тобто i стане одно 2) і знову буде виконано оператори, розташовані в його тілі. У результаті будуть визначені елементи z21, z22, ..., z2m другого рядка масиву і т.д.
Друга структура вкладених циклів призначена для обчислення суми позитивних елементів масиву z. Для цього спочатку змінної s буде присвоєно значення 0, а потім у вкладених циклах буде накопичена необхідна сума в клітинку s.
13.9. Оператор запису With
У ранніх версіях мови оператор використовувався для більш зручного доступу до полів запису.
Приклад:
Var
Student: Record
Fam: String [30];
Name: String [20];
Age: Word;
End;
...
Student.Fam: = 'Колокольников';
Student.Name: = 'Павло';
S: = Student.Fam + '' + Student.Name;
{Попередніх три оператори еквівалентні наступним}
With Student do
Begin
Fam: = 'Колокольников';
Name: = 'Павло';
S: = Fam + '' + Name;
End;
13.10. Оператор Try - Except - End
Це новітнє засіб мови. Блок Try - Except - End використовується для запобігання виняткових ситуацій (ІС), які можуть виникнути при виконанні програми. До їх числа відносяться збої в роботі апаратури, помилки обчислень (наприклад розподіл на нуль), спроби привласнити значення, що виходить за межі типу і т. д.
Синтаксис:
Try
{Оператори, здатні генерувати ІС}
Except
{Оператори, обробні генеровані ІС}
end;
Блок Try - Except - End працює наступним чином. Виконання починається з операторів, розташованих в блоці Try - Except. Якщо в будь-якому операторі виникає ІС, то вона придушується і потім виконуються всі оператори, які працюють у блоці Except - End. У результаті запобігається аварійне переривання програми. Використання блоку Try - Except - End відкриває можливість програмного контролю за ІС.
Приклад.
i: = 0;
n: = 8;
Try
i: = n div i; {Поділ на нуль. Оператор генерує ІС}
n: = i + 9;
Except
ShowMessage ('Помилка. Поділ на нуль в операторі i: = n / i');
End;
Результатом виконання блоку операторів буде поява на екрані форми з повідомленням "Помилка. Поділ на нуль в операторі i: = n / i", після чого програма продовжить роботу з оператора, наступного за словом End, а не з оператора n: = i + 9 .
Якби оператор i: = n div i не був захищений блоком Try - Except - End, то виникла при його виконанні ІС призвела б до небажаного аварійного завершення програми.
13.11. Оператор On - End
При виникненні ІС мова дозволяє не тільки запобігти переривання програми, а й визначити, якого саме виду була ІС. Для цього в блоці Except - End можна використовувати оператор On-Do.
Приклад
i: = 0; n: = 8;
Try
i: = n div i; {Поділ на нуль. Оператор генерує ІС}
n: = i + 9;
Except
On Ex: EdivByZero do ShowMessage ('Поділ на нуль ");
End;
У цьому прикладі повідомлення про виникнення ІВ буде видано тільки у випадку, коли ІВ буде тільки розподіл на нуль (EdivByZero). У всіх інших випадках ІВ буде відвернена, однак ніякого повідомлення про її виникнення видано не буде. Оголошена в блоці Except - End мінлива Ex може бути будь-яким ім'ям (тут Ex використовується тільки для прикладу).
13.12. Оператор Try - Finally - End
Блок Try - Finally - End також використовується для запобігання ІС, які можуть виникнути при виконанні програми. На відміну від блоку Try - Except - End блок Try - Finally - End використовується для звільнення ресурсів пам'яті, закриття файлів та ін у разі виникнення ІС.
Синтаксис:
Try
{Оператори, здатні генерувати ІС}
Finally
{Оператори звільнення ресурсів пам'яті}
end;
Блок Try - Finally - End працює наступним чином. Виконання починається з операторів блоку Try - Finally, які в правильно написаній програмі повинні містити оператори виділення ресурсів пам'яті. Якщо в будь-якому операторі виникає ІС, то управління відразу передається до операторів блоку Finally - End, де виробляється звільнення пам'яті, закриття файлів і пр. У результаті, з одного боку, запобігає аварійне переривання програми і, по друге, коректно звільняється раніше зарезервована пам'ять, виконується ряд інших необхідних операцій.
Відзначимо, що блок Finally - End виконується завжди поза залежності від того, була чи не була згенерована ІС.
Приклад.
i: = 0;
n: = 8;
Try
GetMem (p, 8000); {виділення пам'яті}
i: = n div i; {Поділ на нуль. Оператор генерує ІС}
n: = i + 9;
Finally
FreeMem (p, 8000); {звільнення пам'яті}
End;
14. Покажчики
У мові є засіб, що дозволяє запитувати пам'ять динамічно, тобто за потребою. Це дозволяє зменшити об'єм коду програми і економно витрачати оперативну пам'ять. Такий засіб являє собою спеціальний тип, званий покажчиком. Є два типи вка-ників: покажчик на об'єкт певного типу і покажчик без типу.
Тип Pointer утворює покажчик без типу. Покажчик на тип має синтаксис:
^ Ім'я типу
Приклади оголошення покажчиків:
Type
tDinArr = Array [1 .. 1000, 100] of String [255]; {звичайний тип}
tDinArrPtr = ^ tDinArr; {покажчик на тип tDinArr}
tRecPtr = ^ tRec; {покажчик на тип запису, який описаний нижче}
tTRec = Record {звичайний тип-запис}
A: Integer;
B: Real;
C: String [255];
End;
Var
DinArr: tDinArr; {звичайна запис}
DinArrPtr: tDinArrPtr; {покажчик на тип}
RecPtr: tRecPtr; {покажчик на тип-запис}
Pn1, Pn2: Pointer; {покажчики без типу}
Модулі System і SysUtils містять велику кількість типів для роботи з вказівниками. Ці типи можуть бути використані для підвищення ефективності програм користувача, в яких використовуються покажчики. До їх числа належать: PAnsiString, PString, PByteArray, PCurrency, PExtended і ряд інших покажчиків. Втім, ці типи можуть бути легко замінені стандартними типами. Наприклад PString еквівалентний ^ String і т.д.
14.1. Операції з вказівниками
Для покажчиків припустимі операції привласнення і порівняння. Вказівником можна присвоювати:
вміст покажчика такого ж типу;
константу Nil (порожній покажчик);
адреса об'єкту за допомогою функції Addr;
адресу з допомогою оператора @;
адреса, побудований функцією Ptr.
Приклад:
TrPt: = Nil;
Klo1Ptr: = Klo2Ptr;
P1: = @ Pp; {еквівалентно P1: = Addr (Pp);}
P2: = Ptr ($ B701);
14.2. Стандартні процедури та функції для роботи з вказівниками
Procedure GetMem (Var: P: Pointer; Size: Word);
Виділяє блок пам'яті розміру Size і привласнює адресу початку блоку вказівником P.
Procedure FreeMem (Var: P: Pointer; Size: Word);
Звільняє блок пам'яті розміру Size, адресований покажчиком P.
Нижче наведено докладний приклад, який демонструє економний процес копіювання текстового файлу 't1.txt' в файл 't2.txt' з використанням покажчика Buffer.
Var
F1, F2: file; {оголошення файлових змінних}
Buffer: PChar; {оголошення покажчика на рядок}
begin
AssignFile (F1, 't1.txt'); {зв'язування F1 з файлом 't1.txt'}
Reset (F1, 1); {файл відкритий для вводу / виводу}
AssignFile (F2, 't2.txt'); {зв'язування F2 з файлом 'text.txt'}
Rewrite (F2, 1); {файл відкритий для виведення}
try
Size: = FileSize (F1); {обчислення розміру файлу}
GetMem (Buffer, Size); {виділення пам'яті під читання файлу}
try
BlockRead (F1, Buffer ^, Size); {зчитування всього файлу 't1.txt'}
BlockWrite (F2, Buffer ^, Size); {запис у файл 't2.txt'}
finally
FreeMem (Buffer); {звільнення пам'яті}
end;
finally
CloseFile (F1); {закриття файлу F1}
CloseFile (F2); {закриття файлу F2}
end;
end;
У цьому прикладі оголошений покажчик на рядок Buffer з завершальним нулем, яка буде використана для копіювання файлу 't1.txt' в файл 't2.txt'. Для цього оператором GetMem для змінної Buffer ^ буде динамічно виділено блок пам'яті розміром, рівним розміром файлу. Далі оператором BlockRead файл 't1.txt', пов'язаний файлової змінної F1, буде лічений в Buffer ^ і потім оператором BlockWrite мінлива Buffer ^ буде записана в файл 't2.txt', пов'язаний з файлової змінної F2. Для запобігання виняткових ситуацій приклад містить два вкладених блоку try - finally - end. Внутрішній блок обслуговує можливий збій в ситуації, коли з якої-небудь причини файл не вдалося прочитати або записати операторами BlockRead або BlockWrite. Такий спосіб гарантує звільнення пам'яті оператором FreeMem як у випадку успішного копіювання, так і у випадку можливого збою. Зовнішній блок обслуговує ситуацію, коли у системи можливо немає того обсягу пам'яті, який запитує оператор GetMem. У будь-яких варіантах - при успішному чи безуспішному копіювання файлу - наступні за останнім finally оператори CloseFile закриють відкриті операторами Reset і Rewrite файли F1 і F2 і дозволяє програмі продовжити роботу.
Procedure New (Var: P: Pointer);
Створює нову динамічну змінну того типу, на який посилається вказівник. Еквівалентна оператору GetMem (P, SizeOf (P ^));
Procedure Dispose (Var: P: Pointer);
Знищує динамічну змінну, на яку вказує P. Еквівалентна оператору FreeMem (P, SizeOf (P ^));
Procedure ReallocMem (var P: Pointer; Size: Integer);
Процедура працює наступним чином:
якщо P = Nil і Size = 0, то оператор не виконає ніяких дій;
якщо P = Nil і Size> 0, то оператор спрацює аналогічно GetMem;
якщо P Nil і Size = 0, то оператор спрацює аналогічно FreeMem.
Function Addr (X): Pointer;
Адреса зазначеного імені.
14.3. Інші процедури та функції для роботи з вказівниками
У модулях System і SysUtils оголошені процедури і функції, які можуть знайти застосування в користувальницьких програмах. Нижче подано опис деяких функцій і процедур.
Function GetHeapStatus: THeapStatus;
Розташована в модулі System. Дає зведення про стан розподілений-ної та доступною програмі пам'яті. Тип функції має вигляд
THeapStatus = record
TotalAddrSpace: Cardinal;
TotalUncommitted: Cardinal;
TotalCommitted: Cardinal;
TotalAllocated: Cardinal;
TotalFree: Cardinal;
FreeSmall: Cardinal;
FreeBig: Cardinal;
Unused: Cardinal;
Overhead: Cardinal;
HeapErrorCode: Cardinal;
end;
Function AllocMem (Size: Cardinal): Pointer;
Виділяє блок пам'яті і встановлює кожен байт "в нуль". Освобо-ганізацій пам'яті можна виконати за допомогою процедури FreeMem.
Procedure GetMemoryManager (var MemMgr: TMemoryManager);
Дає поточний стан менеджера пам'яті - спеціального запису з типом:
TMemoryManager = record
GetMem: function (Size: Integer): Pointer;
FreeMem: function (P: Pointer): Integer;
ReallocMem: function (P: Pointer; Size: Integer): Pointer;
end;
Procedure SetMemoryManager (var MemMgr: TMemoryManager);
Встановлює менеджер пам'яті - виконує операції виділення та звільнення пам'яті згідно з попередньо встановленими в менеджері пам'яті значеннями.
14.4. Глобальні змінні AllocMemCount і AllocMemSize
У модулі System оголошені дві глобальні змінні, значення яких можуть бути використані при контролі за динамічно створюваними і руйнують користувацькими змінними.
AllocMemCount - кількість блоків виділеної пам'яті.
AllocMemSize - розмір блоків виділеної пам'яті.
15. Підпрограми
Підпрограма - це закінчена алгоритмічна одиниця, яка призначена для виконання деякого обмеженого по відношенню до використовує її програмі кола операцій.
У мові Object Pascal є два види підпрограм - процедури та функції. Структура будь-якої підпрограми багато в чому нагадує структуру вихідного модуля. Кожна така підпрограма перед її використанням повинна бути описана. Описом підпрограми називається її вихідний код, а зверненням до підпрограми є оператор або його частина, які містять код виклику такої підпрограми. Таким чином, опис - це технологія, а звернення - це дії по визначеній технології.
Будь-яка підпрограма може мати локальні і глобальні по відношенню до неї параметри. Локальним є параметр, дія якого обмежена тільки підпрограмою, в якій він описаний. Хтось інший параметр буде глобальним. Всі глобальні параметри завжди описані за межами підпрограми, в якій вони використовуються.
15.1. Процедури
Будь-яка процедура має заголовок і тіло. Тіло процедури складається з операторів, призначених для опису імен і дій над даними. Синтаксис процедури має вигляд
Procedure procedureName (parameterList); directives;
localDeclarations;
begin
statements;
end;
Тут
Name - ім'я процедури,
parameterList - список формальних параметрів,
directives - директиви,
localDeclarations - внутрішні описи,
statements - оператори тіла процедури.
procedureName - ім'я процедури. Іменем процедури може бути будь-яке ім'я, що не збігається з жодним іншим описаним в тому ж, що і процедура, блоці, ім'ям.
parameterList - список формальних параметрів може бути або порожній (в цьому випадку дужки можна не використовувати), або повинен містити послідовність вхідних та / або вихідних величин. Окрема величина в описі заголовка може бути:
оголошеної за допомогою слова var змінної з типом або без типу;
константою;
вихідною величиною (т. зв. out-параметром).
Приклад опису процедури.
procedure ByRef (var X: Integer; L, K: Integer);
begin
X: = X * 2 * L; {правильно}
K: = 2 + L; {помилка}
end;
Процедура c ім'ям ByRef містить три параметри - змінну X і дві константи L і K. Тіло процедури складається з операторів, укладених в операторних дужках begin - end. Змінні L, K є лише вхідні і не можуть бути змінені в тілі процедури. З цієї причини оператор K: = 2 + L не дасть результату і значення До залишиться таким же, яким воно було до звернення до процедури. Навпаки, змінна X, оголошена за допомогою слова var, буде обчислена і на виході буде мати те значення, яке буде обчислено всередині процедури ByRef.
Out-параметр являє пряму протилежність константі, він повинен бути тільки вихідний, обумовленою всередині процедури, величиною. Наприклад, в наступному коді
procedure GetInfo (out Info: SomeRecordType);
var MyRecord: SomeRecordType;
...
Proc1 (MyRecord);
...
мінлива MyRecord не може передавати дані в процедуру Proc1. Навпаки, тільки Proc1 може сформувати дані і передати їх у MyRecord.
Тип параметра може бути будь-яким. Однак не можна оголошувати новий тип прямо в заголовку підпрограми. Такий тип повинен бути оголошений раніше і тільки після цього може бути використаний у заголовку підпрограми.
localDeclarations - внутрішні описи можуть містити опис локальних імен типів або змінних. У попередньому прикладі мінлива MyRecord типу SomeRecordType, оголошена всередині процедури GetInfo, є зразком такого опису.
directives - директиви використовуються для того, щоб дати компілятору деякі додаткові вказівки про описуваної процедурою. Директиви описані в параграфі 15.3.
Для виклику процедури, тобто для звернення до закладеного в ній алгоритму, слід записати оператор, в якому на місце формальних параметрів повинні бути підставлені фактичні параметри. Наступний приклад містить як опис процедури MatrMult, так і звернення до неї.
Program {початок програми}
...
Const n = 10; {розмір матриць}
Type tMatr = array [1 .. n, 1 .. n] of Real; {тип матриць}
Var Q1, Q2, Q3: tMatr; {опис матриць}
Procedure MatrMult (M1, M2: tMatr; Var M3: tMatr); {заголовок}
Var i, j, k: Integer;
Begin
For i: = 1 to n do
For j: = 1 to n do
Begin {блок визначення одного елемента матриці M3}
M3 [i, j]: = 0;
For k: = 1 to n do
M3 [i, j]: = M3 [i, j] + M1 [i, k] * M2 [k, j];
End;
End; {кінець опису процедури MatrMult}
Procedure Prim; {заголовок процедури Prim}
Var i, j: Integer;
Begin
For i: = 1 to n do {блок завдання елементів матриць Q1, Q2}
For j: = 1 to n do
Begin
Q1 [i, j]: = i + j;
Q2 [i, j]: = i - j;
End;
MatrMult (Q1, Q2, Q3); {оператор звернення до процедури MatrMult}
End; {кінець опису процедури Prim}
... {Текст головний програми}
Prim; {звернення до процедури Prim}
Q3 [2, 3]: = 1;
...
Наведений у даному прикладі текст програми можна розділити на чотири частини:
опис глобальних констант і змінних;
текст процедури MatrMult;
текст процедури Prim;
текст головний програми.
У верхній частині описана глобальна константа n = 10, яка використовується в усіх наступних за цим структурах. Так, у секції Type оголошений тип речового квадратного масиву tMatr. Далі в секції Var оголошені три змінні - матриці Q1, Q2, Q3 типу tMatr.
Далі дано текст процедури MatrMult, яка представляє алгоритм множення матриць M1 і M2 із записом результату в змінну M3. Матриці M1, M2 у процедурі не змінюються, тому їх необов'язково оголошувати змінними (з позицій процедури MatrMult змінні M1, M2 виступають в якості констант). Навпаки, матриця M3 виходить як результат, який визначається всередині процедури MatrMult, тому вона оголошена в заголовку словом Var. Неоголошення M3 як змінної призвело б до помилки: змінені всередині процедури значення цієї матриці не були б зафіксовані. Змінні i, j, k, оголошені усередині процедури, є локальними і діють тільки в межах цієї процедури.
Опис процедур закінчується процедурою Prim. У тілі цієї процедури оголошено дві локальні змінні i, j, виконують допоміжну роль лічильників циклів. Далі розташовано два вкладених один в одного циклу, за допомогою яких визначаються елементи матриць Q1 і Q2. По відношенню до процедури Prim ці матриці є глобальними змінними і, отже, вони доступні не тільки в зовнішньому блоці, але і всередині процедури Prim. І нарешті, в нижній частині розташований оператор звернення до процедури MatrMult, який призначений для виклику алгоритму перемножування матриць.
У нижній частині програми дано фрагмент тексту головний програми, що містить виклик процедури Prim.
Опишемо механізм обчислень, який запускається наведеної програмою. Спочатку буде виконано процедуру Prim (звернення до неї міститься в самій нижній частині тексту прикладу). Ця процедура без параметрів, тому управління буде відразу передано в тіло процедури, де почнеться послідовне виконання містяться в ньому операторів. Спочатку будуть виконані два вкладених циклу For, де елементи матриць Q1, Q2 будуть заповнені значеннями (наприклад Q1 [1, 1] = 2, Q2 [1, 1] = 0 і т. д.). Далі вже всередині Prim відбудеться звертання до процедури MatrMult. При цьому спочатку відбудеться підстановка фактичних параметрів Q1, Q2, Q3 на місце відповідних формальних параметрів M1, M2, M3. Далі управління буде передано всередину процедури MatrMult, де аналогічно послідовним виконанням її операторів відбудеться перемножування матриць. Після виконання процедури MatrMult управління буде передано в ту ж точку, з якої проводився її виклик. Оскільки виклик MatrMult проводився з Prim, то управління буде знову повернуто в процедуру Prim до оператора, розташованому слідом за оператором виклику MatrMult. Оскільки в Prim більше немає невиконаних операторів, то вона також закінчує свою роботу і управління передається в ту алгоритмічну одиницю, яка і викликала Prim, а саме в головну програму, до оператора Q3 [2, 3]: = 1.
15.2. Функції
На відміну від процедури функція призначена для обчислення одного значення будь-якого типу. Тип функції вказується в кінці її заголовка. Тип значення, що повертається відокремлюється від списку формальних параметрів символом ":" (двокрапка). Крім того, в тілі функції, принаймні, один раз має бути визначено значення функції. Це значення привласнюється імені функції або змінною Result.
Синтаксис функції має вигляд
function functionName (parameterList): returnType; directives;
localDeclarations;
begin
statements;
end;
Тут functionName - ім'я функції; ParameterList, directives, localDeclarations, statements мають той же зміст, що і в процедурі; ReturnType - тип повертається результату.
Приклад.
Function Fact (n: Word): LongInt; {заголовок функції Fact}
Var i: Word; j: LongInt;
Begin
j: = 1;
if (n> 1) then
For i: = 2 to n do j: = j * i;
Result: = j;
End; {кінець опису функції Fact}
... {Текст головний програми}
Var r: Real;
...
r: = 3.4 * Fact (3) / 2.5 / (122 - Fact (5)); {звернення до функції Fact}
...
У цьому прикладі описана функція з ім'ям Fact обчислення факторіала n! неотрицательного цілого числа. Тип функції визначений як LongInt. У тілі функції розміщений оператор Result: = j, який визначає повертається функцією результат. Спосіб звернення до функції демонструє останній оператор прикладу. Видно, що спосіб звернення до функції має істотну відмінність від способу звернення до процедури. Так, в цьому операторі звернення до функції Fact проводиться двічі - один раз з фактичним параметром 3, інший - з параметром 5. Далі повернуті результати (відповідно, 6 і 120) будуть підставлені у вираз правої частини оператора, після чого останній буде вирахувано і мінлива r отримає речовий (Real) значення 4.08.
15.3. Параметри без типу
Це особливий вид параметрів, який може бути використаний тільки в заголовках імен процедур і функцій. Кожен параметр без типу повинен бути описаний як var, const або out-параметр. Наприклад:
procedure TakeAnything (const C);
описує С як константу без типу.
Параметр без типу компілятор розцінює як параметр потенційно будь-якого типу. Це означає, що в тіло підпрограми передається тільки адресу параметра і компілятор не контролює правильність виконання операцій над таким параметром.
Проте є одне виключення: при зверненні до підпрограм, що містить параметри без типу, не можна використовувати числові значення або нетипізовані числові константи.
Наступний приклад використовує параметри без типу у функції Compare, яка порівнює розміри двох змінних V1 і V2 і повертає відповідь у вигляді константи -1, якщо розмір V1 менше розміру V2, нуль - якщо розміри однакові, 1 - якщо розмір V1 менше розміру V2.
function Compare (var V1, V2): ShortInt;
Var i, j: LongInt;
Begin
I: = SizeOf (V1);
J: = SizeOf (V2);
If (I <J) then Result: = -1
Else
If (I> J) then Result: = 1
Else Result: = 0;
End;
Приклади звернень до функції Compare:
type
TVector = array [1 .. 10] of Integer;
TPoint = record
X, Y: Integer;
end;
var
Vec1, Vec2: TVector;
N, i: Integer;
P: TPoint;
...
i: = Compare (Vec1, Vec2); {0, розміри однакові}
Vec [1]: = Compare (i, Vec1); {-1, розмір i менше розміру Vec1}
PX: = Compare (Vec1, P); {1, розмір Vec1 більше розміру P}
PY: = Compare (i, P); {-1, розмір i менше розміру P}
Vec2 [8]: = Compare (i, PX); {0, розміри i і поля PX однакові}
...
15.4. Декларації процедур і функцій
Заголовок процедури або функції може містити декларацію. Декларація вказується відразу слідом за списком параметрів у процедурі або за типом повертається результату у функції.
1. Декларації про виклик за угодою (calling convention). До їх числа відносяться декларації register, pascal, cdecl, stdcall і safecall, наприклад:
function MyFunction (X, Y: Real): Real; cdecl;
Цей вид декларацій призначений для завдання способу передачі параметрів у процедуру. Декларації register, pascal передають параметри зліва направо, cdecl, stdcall і safecall - навпаки, справа наліво.
Директиви near, far і export призначені для розмежування способів поводження в 16-розрядних додатках. Для сучасних 32-розрядних додатків вони не мають значення.
Зазначимо, що згадані декларації використовуються у складних, дуже тонких ситуаціях і для початківця програміста не становлять великого інтересу.
2. Директива Forward вказує на те, що заголовок процедури або функції оголошено раніше, ніж описана сама підпрограма, наприклад:
function Calculate (X, Y: Integer): Real; forward;
...
function Calculate;
...
begin
...
end;
3. Директива External вказує на те, що текст процедури міститься в окремому об'єктному (відкомпілювався) модулі. Такий спосіб дозволяє приєднати об'єктний код до компільованої програмі із зазначеного модуля. Для цього необхідно вказати директиву компілятора з посиланням на модуль, в якому міститься об'єктний код декларованої процедури, наприклад:
{$ L BLOCK.OBJ}
...
procedure MoveWord (var Source, Dest; Count: Integer); external;
procedure FillWord (var Dest; Data: Integer; Count: Integer); external;
Цей приклад показує, що при компіляції коди процедур MoveWord і FillWord слід шукати в об'єктному коді BLOCK.OBJ.
4. Директива OverLoad дозволяє використовувати одне ім'я для декількох підпрограм, наприклад:
function Divide (X, Y: Real): Real; overload;
begin
Result: = X / Y;
end;
function Divide (X, Y: Integer): Integer; overload;
begin
Result: = X div Y;
end;
У цьому прикладі описані дві функції з одним ім'ям Divide. При зверненні до функції з таким ім'ям викликана буде та функція, фактичні параметри якої відповідають формальним параметрам. Так, при зверненні у вигляді Divide (6.8, 3.2) буде викликана перша функція, тому що її формальні параметри також речовинні, а при зверненні Divide (6, 8) буде викликана друга функція.
Директива Overload дозволена для підпрограм, в яких можуть розрізнятися тільки типи параметрів, тому неприпустимі опису виду
function Cap (S: string): string; overload;
procedure Cap (var Str: string); overload;
15.5. Процедурні типи
Процедурні типи допускають використання процедур і функцій у вигляді значень, які можуть бути присвоєні змінним або передані в інші процедури або функції. Наприклад, в наступному прикладі визначена функція Calc з двома цілочисельними формальними параметрами X, Y, що повертає цілий тип:
function Calc (X, Y: Integer): Integer;
Ця функція може бути визначена як тип для змінної F:
var F: function (X, Y: Integer): Integer;
і пов'язана з цієї змінної оператором присвоювання:
F: = Calc;
Точно так само можна визначити будь-який інший новий процедурний тип і змінну:
Type {оголошення процедурних типів}
TIntegerFunction = function: Integer;
TProcedure = procedure;
TStrProc = procedure (const S: string);
TMathFunc = function (X: Double): Double;
Var {оголошення процедурних змінних}
F: TIntegerFunction; {F функція без параметрів, що повертає ціле}
Proc: TProcedure; {Proc - процедура без установки}
SP: TStrProc;
M: TMathFunc;
При використанні операторів над процедурними типами і процедурами або функціями необхідно розрізняти зв'язування процедурної змінної і звернення до процедури або функції. Так в наступному прикладі оголошуються мінлива F типу функції, а змінна I - простого цілочисельного типу, потім слідує текст процедури SomeFunction:
F: function (X: Integer): Integer;
I: Integer;
function SomeFunction (X: Integer): Integer;
...
У операторної частини перший оператор пов'язує F з конкретною функцією, не виробляючи над нею ніяких дій:
F: = SomeFunction;
навпаки, оператор
I: = F (4);
викликає цю функцію (запускає її алгоритм) і після обробки повертає результат обчислень змінної I.
15.6. Формальні і фактичні параметри
У Object Pascal є поняття формального і фактичного параметрів. Формальним називається параметр, який міститься в заголовку опису підпрограми, а фактичним - параметр у зверненні до підпрограмі. Так, у вищенаведеному прикладі параметр X є формальним, а значення 4 - фактичним.
При виклику підпрограм необхідно мати на увазі наступне:
фактичні значення або константи повинні бути сумісні за типом з оголошеними формальними параметрами;
фактичні var або out-параметри повинні бути ідентичні за типом оголошеним формальним параметрам, виключенням є тільки нетипізовані параметри;
формальним параметрам без типу не можуть відповідати такі фактичні параметри, як числові значення та нетипізовані число-ші константи.
Наведемо ще один приклад, який демонструє способи звернення до підпрограм.
Const
IntCount = 1200;
Type
TFunc12 = Function (c1, c2: Integer): Integer;
Function Func12_1 (k1, k2: Integer): Integer;
Begin
Result: = k1 + k2;
End;
Function Func12_2 (g1, g2: Integer): Integer;
Begin
Result: = g1 - g2;
End;
Procedure AnyPro (u1: Real; Var u2: Real; Var u3; Const u4: Integer; F: tFunc12);
Begin
u2: = u1 + u4 + F (u4, Round (u4 * 3.14));
u3: = u1 - u4 - F (u4, Round (u4 * 3.14));
End;
Var
k: Integer;
v1, v2: Real;
ss: String;
...
{Приклади звернення до процедури AnyPro:}
AnyPro (v1, v2, v1, v2, Func12_1);
AnyPro (v1, v2, ss, v1, Func12_2);
AnyPro (k, v1, ss, v2, Func12_1);
AnyPro (k + 8, v2, ss, IntCount, Func12_1);
AnyPro (8, v2, ss, v1 +6.7, Func12_2);
Параметри u1, u2, u3, u4, F в заголовку процедури AnyPro, є формальними параметрами: u1 - константа типу Real; u2 - змінна типу Real; u3 - мінлива без типу; u4 - константа типу Integer; F - параметр-функція типу TFunc12 , який оголошено вище в секції Type.
Параметри, укладені в дужки в прикладах звернення до процедури AnyPro, є фактичними параметрами. Такі параметри можуть бути значеннями (8), константами (IntCount), змінними (v1), виразами (k + 8), іменами процедур або функцій (Func12_1) і ін
15.7. Область дії імен
У підпрограмах частина параметрів може бути оголошена прямо в заголовку або її тілі. Такі параметри діють лише всередині цієї підпрограми і тому називаються локальними параметрами. У той же час в підпрограмі можна використовувати параметри, які описані за межами підпрограми. Такі параметри називаються глобальними параметрами.
Глобальні параметри можуть бути описані в тому ж модулі, який містить використовує їх підпрограму, або в іншому модулі, на який є посилання у списку uses. Якщо два параметри мають однакове ім'я і один з них описаний усередині підпрограми, а інший - за її межами, то діє той параметр, який описаний в підпрограмі. Аналогічно визначається область доступності параметрів описаних в різних модулях. Таким чином, при описі імен діє такий принцип: більш пізній оголошення скасовує облаcтей дії раніше описаних імен. Всередині однієї підпрограми не можна оголошувати двох і більше однакових імен.
Пояснимо область дії імен на прикладі наступного модуля
Unit Mod4;
interface
uses Mod1, Mod2, Mod3;
....
Type
Vr = Integer; {допустимо}
...
Var
Vr: Real; {неприпустимо}
...
implementation
Var Vr: Char; {неприпустимо}
...
procedure Pro1; {не містить внутрішнього оголошення імені Vr}
...
procedure Pro2; {містить внутрішнє оголошення імені Vr}
Var
Vr: String; {допустимо}
Vr: Real; {неприпустимо}
...
У наведеному тексті модуля Mod4 міститься кілька описів імені Vr, частина яких допустима, інша частина помилкова. Неприпустимо опис цього імені:
в var-секції в розділі interface, так як воно вже використано в цьому ж розділі вище - в секції type;
в var-змінної в розділі implementation, так як воно вже використано в цьому ж модулі в розділі interface;
як змінної типу Real в тілі процедури Pro2, тому що воно вже використано в цій же процедурою при описі String-змінної.
Більш пізніше оголошення скасовує дію раніше описаного імені. Так, усередині процедури Pro2 ім'я Vr представляє змінну типу String, а всередині процедури Pro1 ім'я Vr діє як глобальний тип Integer, оголошений вище - в секції type.
Якщо б це ім'я взагалі не було описано в модулі Mod4, але було б оголошено в одному або декількох модулях, зазначених у посилальної списку uses, то воно могло б бути використане як глобальний параметр всередині цього модуля (Mod4). При цьому діяло б то ім'я, яке оголошено в розділі interface самого останнього містить його модуля списку uses. Наприклад, якщо є опис імені Vr в модулях Mod1 і Mod2, то діяв би опис з Mod2. Якщо в списку uses поміняти Mod1 і Mod2 місцями, то буде діяти опис, який виконано для цього імені в модулі Mod1.
Слід виявляти особливу обережність при використанні глобальних змінних в підпрограмах. Наведений нижче приклад демонструє непередбачувана поведінка програми, що використовує функцію Deccy і глобальний по відношенню до неї параметр d:
Function Deccy (x: Integer): Integer;
Begin
d: = d - x;
Deccy: = Sqr (x);
End;
...
d: = 3; a: = Deccy (3) * Deccy (d); {a = 0, d = 0}
d: = 3; a: = Deccy (d) * Deccy (3); {a = 81, d = -3}
Приклад показує, що два, здавалося б, коректних способу звертання-ня до функції дають тим не менш різні результати обчислень.
15.8. Рекурсивні процедури та функції
У Object Pascal допустимо звернення підпрограми до самої себе (рекурсивне звернення). При такому зверненні параметри, які використовує підпрограма, заносяться в стек і зберігаються там до кінця роботи підпрограми. Рекурсивні підпрограми є надзвичайно зручним, нерідко незамінним інструментом побудови ефективних алгоритмів. Зворотним боком рекурсивних процедур є небезпека переповнення стека, що часто обмежує можливість написання таких алгоритмів.
В якості ілюстрації наведемо приклад простий і надзвичайно ефективної процедури сортування (розстановки елементів в порядку неспадання) фрагмента цілочисельного одновимірного масиву A:
procedure QuickSortPart (var A: array of Integer; iLo, iHi: Integer);
var
Lo, Hi, Mid, T: Integer;
begin
Lo: = iLo;
Hi: = iHi;
Mid: = A [(Lo + Hi) div 2]; {середній елемент фрагмента}
repeat {поділ фрагменту на ліву і праву частини}
while A [Lo] <Mid do Inc (Lo);
while A [Hi]> Mid do Dec (Hi);
if Lo Hi;
if Hi> iLo then QuickSortPart (A, iLo, Hi); {сортування лівій частині}
if Lo <iHi then QuickSortPart (A, Lo, iHi); {сортування правій частині}
end;
Процедура QuickSortPart сортує фрагмент одновимірного масиву A, що починається індексом iLo і закінчується індексом iHi. Процедура полягає в методі половинного ділення. У відповідності з цим методом спочатку вибирається елемент, розташований в середині сортованого фрагмента, потім елементи менші його відправляються в ліву частину фрагмента, інші - в праву частину. Далі сортуються ліва і права частини розділеного масиву як окремі фрагменти за тією ж схемою, тобто до кожної з них застосовується та ж процедура QuickSortPart. Саме звернення процедури до самої себе і робить її рекурсивної.
Нижче наведена звичайна (нерекурсивний) процедура QuickSort сортування всіх елементів масиву, яка виконується зверненням до рекурсивної процедури QuickSortPart, де фрагмент - весь масив A.
procedure QuickSort (var A: array of Integer);
begin
QuickSortPart (A, Low (A), High (A));
end;
15.9. Параметри і конструктори відкритих масивів
Відкриті масиви допускають передачу масивів різного розміру в якості параметрів у процедурах та функціях. У цьому випадку можна оголосити масив у вигляді
array of type (переважно array [X .. Y] of type)
Наприклад, оператори
procedure NullChar (A: array of Char);
begin
for i: = Low (A) to High (A) do A [i]: = '0 ';
end;
оголошують процедуру NullChar, яка містить один параметр - відкритий символьний масив А будь-якого розміру. У тілі процедури використовується оператор циклу, який заповнює кожен елемент масиву символом "0". Для визначення нижньої межі індексу використана стандартна функція Low, для верхньої - High.
Якщо до такої процедури звернутися оператором NullChar (z), де тип змінної z = array [5 .. 55] of Char, то весь масив z буде заповнений символами "нуль".
Конструктори відкритих масивів допускають конструювання значень таких масивів прямо усередині оператора звернення до підпрограми.
Приклад:
var I, J: Integer;
procedure Add (A: array of Integer);
У цьому випадку можна звернутися до процедури Add, наприклад, так:
Add ([5, 7, I, I + J]);
16. Структура програми
У середовищі Delphi програма як єдине ціле представляється у вигляді проекту. У новій версії мови Object Pascal для представлення проекту використовується п'ять основних типів файлів:
dpr-файл головний програми;
текстові pas-файли;
відкомпілювалися dcu-файли;
res-файли ресурсів;
dfm-файли ресурсів екранних форм;
готові до використання програмні exe-файли.
Вихідна програма, написана в середовищі Delphi на мові Object Pascal завжди складається з декількох модулів, кожен з яких розміщується в окремому текстовому файлі. Один модуль є головною програмою. Він починається словом Program і розміщується у файлі з розширенням. Dpr. Всі інші модулі є підлеглими і починаються словом Unit. Такі модулі розміщуються у файлах з розширенням. Pas. Всі модулі закінчуються оператором End, після якого ставиться символ "крапка".
Кожен модуль може використовувати інші модулі, до числа яких можуть відноситися текстові файли, res-і dfm-файли ресурсів або відкомпілювалися файли Unit-модулів. Сcилка на необхідні до використання модулі міститься в секціях Uses. Текстові або скомпільовані файли зазвичай містять необхідні для використовує їх модуля величини - константи, типи, змінні, процедури і функції. Файли ресурсів необхідні для підключення констант, що описують використовувані зовнішні ресурси.
Перераховані вище модулі, розміщені в *. pas-, *. dcu-, *. res-, *. dfm-файлах, відіграють допоміжну роль: вони призначені для компіляції і подальшого складання в повноцінний програмний модуль - exe-файл, готовий до виконання на комп'ютері.
Нижче наведено приклад вихідних текстів головний програми KdnBread і одного підлеглого (використовуваного) нею модуля Main.
Program KdnBread; {початок тексту головний програми}
{Текст міститься у файлі 'c: BorlandProjectsKdnBread.pas'}
uses {посилання на модулі типу unit}
Forms, {посилання на модуль Forms}
main in 'main.pas' {Form1}; {посилання на модуль main}
{$ R *. RES}
begin
Application.Initialize;
Application.CreateForm (TForm1, Form1);
Application.Run;
end. {Кінець тексту головний програми}
unit Main; {початок тексту модуля Main}
{Текст модуля міститься у файлі 'c: BorlandProjectsMain.pas'}
interface {початок інтерфейсної частини модуля}
uses
Windows, Messages, SysUtils, {посилання на інші модулі}
Graphics, Controls, Forms, StdCtrls;
Type {опис типів}
TForm1 = class (TForm)
Button1: TButton;
L1: TLabel;
procedure Button1Click (Sender: TObject);
private
{Private declarations}
public
{Public declarations}
end;
Var {опис змінних}
Form1: TForm1;
b: boolean;
i: Integer;
IterationPar: Word;
functio n OneSymbString (c: Char; d: byte): String; {заголовок функції}
implementation {початок процедурного блоку модуля}
{$ R *. DFM}
procedure TForm1.Button1Click (Sender: TObject); {заголовок процедури}
begin
if (i> 12) and b then
L1.Caption: = 'Студент:' + AnsiUpperCase ('Іванов Володимир Іванович');
end; {кінець процедури}
function OneSymbString (c: Char; d: byte): String; {заголовок функції}
begin
Result: = CharStr (c, d);
end; {кінець функції}
initialization
IterationPar: = 0;
end. {Кінець тексту модуля Main}
Виконання програми завжди починається з модуля Program, тобто з головним програми. Program активізує виконання процедур і функцій у використовуваних нею модулях Unit.
16.1. Структура модуля
Модуль має наступну структуру:
Unit;
interface
implementation
initialization
finalization
end.
16.2. Розділ Interface
Розділ Interface модуля Unit призначений для опису зовнішніх компонент: використовуваних модулів, типів, констант, змінних, заголовків процедур і функцій. Так, у вищенаведеному прикладі в розділі Interface містяться:
у списку Uses - посилання на модулі Windows, Messages, SysUtils, Graphics, Controls, Forms, StdCtrls;
в секції Type - опис типу екранної форми - клас TForm1;
в секції Var - опис змінних Form1, b, i і опис заголовки-ка функції OneSymbStr, призначеної для створення рядка повторюю-трудящих d раз символів Ch.
16.3. Розділ Implementation
Розділ Implementation модуля Unit призначений для опису внутрішніх, тобто доступних до використання тільки всередині даного Unit, компонент: типів, констант, змінних, процедур і функцій. Так, у вищенаведеному прикладі в розділі Implementation міститься опис процедури TForm1.Button1Click (Sender: TObject) і функції OneSymbStr.
16.4. Ініціювання та завершення модуля
Кожен модуль може містити блок ініціювання і блок завершення. Ці блоки розташовуються в нижній частині модуля, безпосередньо примикаючи до останнього оператору end. Перший блок починається словом initialization, другий - словом finalization.
Блок ініціювання initialization закінчується останнім оператором end модуля або, при наявності блоку завершення, триває до слова finalization.
Зазвичай в блоці ініціювання розташовуються оператори визначення початкових значень яких-небудь змінних, виділення ресурсів пам'яті, відкриття файлів і пр., тобто все те, що необхідно ініціалізувати в модулі до передачі керування в використовують його модулі.
Блок завершення може бути використаний тільки в тому випадку, якщо модуль має блок ініціювання. Цей блок, на противагу блоку ініціювання, призначений для розміщення операторів завершення, тобто операторів звільнення ресурсів пам'яті, закриття раніше відкритих в блоці ініціювання файлів і пр.
Наприклад, модуль може закінчуватися наступними операторами:
...
Initialization {ініціювання}
Ga: = 0;
AssignFile (f, 'c: ProjectsBreadProFirst.dat');
Reset (f, SizeOf (Rec1));
New (AppMem);
Finalization {завершення}
Dispose (AppMem);
CloseFile (f);
End. {Останній оператор модуля}
Якщо кілька модулів мають блоки ініціювання, то вони виконуються в тому порядку, в якому імена модулів розташовуються в списку Uses головний програми. Якщо кілька модулів містять блоки завершення, то вони виконуються в порядку, протилежному порядку перерахування модулів у списку uses головний програми.
17. Файли
Файлом називається область даних на зовнішньому носієві - жорсткому диску, дискеті та ін Кожен файл має ім'я, яке представляє собою рядок символів. Розрізняють звичайне ім'я (або просто ім'я) і повне ім'я. Під повним ім'ям розуміється абсолютний адресу файлу, що складається з шляху і імені файлу. Наприклад, рядок 'C: Program FilesFolder1Students.dat' є повним ім'ям. Воно складається з шляху 'C: Program FilesFolder1' до файлу і власне імені файлу 'Students.dat'. Це означає, що файл 'Students.dat' розташований на диску C в папці (директорії) Program Files безпосередньо в папці (субдіректоріі) Folder1.
Раніше згадувалося, що в мові Object Pascal існує три типи файлів:
= TextFile; {текстові файли}
= File; {файли без типу}
= File of; {файли з типом}
| | | 17.1. Файлова змінна Для того щоб отримати доступ до файлу, його необхідно спочатку відкрити. Відкриття файлу виконується за допомогою зв'язування файлу з особливою змінної, званої файлової змінної. Саме файлова змінна і характеризує тип файлу. Зв'язування файлу з файлової змінної ще не означає відкриття цього файлу. Відкриття файлу здійснюється спеціальними процедурами, про які буде згадано нижче. Зв'язування файлу з файлової змінної проводиться за допомогою стандартної процедури AssignFile, яка має заголовок: AssignFile (,); Наприклад, фрагмент Var f1: TextFile; FullPath: String [60]; ... FullPath: = 'a: a1.res'; AssignFile (f1, FullPath); містять задану оголошення файлової змінної f1 текстового типу і рядка FullPath, які потім використовуються у виконавчій частини для вказівки повного імені файлу і зв'язування його з файловою змінною f1. 17.2. Текстові файли Текстовий файл - це послідовність символьних рядків змін-ної довжини. Будь-яка рядок завершується маркером кінця рядка, всякий текстовий файл завершується маркером кінця файлу. Такі файли можна обробляти тільки послідовно. Один і той же текстовий файл не може бути відкритий одночасно для введення і виведення. Файлова змінна цього файлу має тип TextFile або просто Text. Для текстових файлів є дві стандартні файлові змінні - Input і Output, які не потрібно оголошувати окремо. 17.2.1. Процедури і функції для роботи з текстовим файлом Procedure AssignFile (f: TextFile; FileName: String); Пов'язує файлову змінну f з дисковим файлом FileName. Procedure Append (f: TextFile); Відкриває існуючий файл для додавання рядків у кінець файлу. За відсутності файлу виникає помилка вводу / виводу. Procedure Rewrite (f: TextFile); Створює новий файл і відкриває його для виводу. Якщо файл існує, то він знищується і створюється як новий. Коли новий текстовий файл закривається, до нього автоматично додається маркер кінця файлу. Procedure Reset (f: TextFile); Відкриває існуючий файл для читання і встановлює вказівник на перший рядок файлу. При його відсутності виникає помилка вводу / виводу. Procedure Read (f: TextFile [; v1, v2, ..., vN]); Читає дані з файлу і заносить їх у змінні v1, v2, ..., vN. Змінні можуть мати символьний, рядковий чи арифметичні типи. Procedure Readln (f: TextFile [; v1, v2, ..., vN]); Читає дані з файлу цілими рядками і заносить їх у змінні v1, v2, ..., vN. Якщо список змінних порожній, то відбувається переміщення покажчика на наступний рядок. Procedure Write (f: TextFile [; v1, v2, ..., vN]); Записує дані з змінних v1, v2, ..., vN у файл у символьному вигляді. Procedure SetTextBuf (f: TextFile; Var Buf [; Size: Integer]); Встановлює буфер читання текстового файлу. Процедура має бути викликана після AssignFile, але до першого виклику процедур читання. Буфер використовується для читання великих фрагментів файлу, включаючи символи кінця рядків. Якщо розмір буфера не вказаний, то за замовчуванням він приймається рівним 128. Procedure CloseFile (f: TextFile); Закриває текстовий файл. Procedure Flush (f: TextFile); Виводить вміст внутрішнього буфера у файл. Function Eof (f: TextFile): boolean; Повертає True, якщо досягнуто кінець файлу. Function Eoln (f: TextFile): boolean; Повертає True, якщо досягнуто кінець поточного рядка. Function SeekEof (f: TextFile): boolean; Повертає статус кінця файлу. Function SeekEoln (f: TextFile): boolean; Повертає статус кінця рядка. Приклад: Var F1, F2: TextFile; Ch: Char; St: String [255]; Buf: array [1 .. 4096] of Char; {текстової буфер розміром 4K} begin AssignFile (F1, 'T1.TXT'); SetTextBuf (F1, Buf); {великий буфер для прискорення читання} Reset (F1); {F1 відкритий для читання} AssignFile (F2, 'WOOF.DOG'); Rewrite (F2); {F2 створений як новий для виведення} while not Eof (F1) do {поки не досягнуто кінець файлу - виконувати} begin Read (F1, Ch); {читає один символ з файлу F1} Write (F2, Ch); {пише один символ в файл F2} end; CloseFile (F1); {файл F1 закритий} CloseFile (F2); {файл F2 закритий} Reset (F1); {F1 знову відкритий для читання} Rewrite (F2); {F2 знову створений для виведення} while not Eof (F1) do {поки не досягнуто кінець файлу - виконувати} begin Readln (F1, St); {читає рядок з файлу F1} Write (F2, St); {пише рядок у файл F2} end; CloseFile (F1); {файл F1 закритий} CloseFile (F2); {файл F2 закритий} end; Наведений фрагмент модуля є демонстраційним і призначений для копіювання файлу 'T1.TXT' в файл 'WOOF.DOG'. У першому циклі While - do копіювання ведеться посимвольний, у другому циклі - порядково. Приклад процедури, записуючої в кінець текстового файлу рядок символів: Procedure AddStrToTextFile (nF, St: String); Var f: Text; Begin AssignFile (f, nF); If not FileExists (nF) then Rewrite (f) {не існує, створити і відкрити} Else {інакше} Begin Reset (f); {існує, відкрити} While not Eof (f) do Readln (f); {пересунути вказівник в кінець файлу} End; Writeln (f, St); {записати рядок} CloseFile (f); {закрити файл} End; До процедури можна звернутися, наприклад, так: Var S1: String [58]; S2: String [189]; ... AddStrToTextFile ('c: Filesring.txt', 'Рядок символів'); AddStrToTextFile ('ring.txt', S1); AddStrToTextFile ('ring.txt', S2); 17.3. Файли з типом Файл складається з будь-яких однотипних компонент. Доступ до даних здійснюється через файлову змінну. На відміну від текстового файлу в такому файлі допустимо прямий доступ до будь-якого запису, причому в рамках відкритого файлу припустиме як записувати, так і читати записи. Приклади оголошення файлової змінної для файлів з типом: Var F1: File of String [45]; F2: File of Real; F3: File of tRecord24; Після кожного читання або виведення запису покажчик автоматично встановлюється на наступний запис. 17.3.1. Процедури і функції для роботи з типізованих файлів Procedure AssignFile (f: File of Type; FileName: String); Пов'язує файлову змінну f з дисковим файлом FileName. Procedure Rewrite (f: File of Type); Створює новий файл і відкриває його. Якщо файл існує, то він знищується і створюється як новий. Procedure Reset (f: File of Type); Відкриває існуючий файл і встановлює вказівник на перший запис. За відсутності файлу виникає помилка вводу / виводу. Procedure Read (f: File of Type [; v1, v2, ..., vN]); Читає запису з файлу і заносить їх у змінні v1, v2, ..., vN. Читання починається з того запису, на яку встановлено вказівник. Типи файлу і змінних повинні бути однакові. Procedure Write (f: File of Type [; v1, v2, ..., vN]); Записує дані з змінних v1, v2, ..., vN у файл. Висновок даних починається з того запису, на яку встановлено вказівник. Якщо покажчик встановлений на існуючий запис, то при виводі вона буде заміщена новим записом. Якщо одночасно виводиться кілька записів, то буде заміщено така ж кількість існуючих записів. Типи файлу і змінних повинні бути однакові. Procedure Seek (f: File of Type; N: LongInt); Переміщає покажчик на запис з номером N. Перший запис має порядковий номер 0. Function FilePos (f: File of Type): LongInt; Повертає номер запису, на яку встановлено вказівник. Procedure CloseFile (f: File of Type); Закриває файл. Function Eof (f: File of Type): boolean; Повертає True, якщо досягнуто кінець файлу. Function FileSize (f: File of Type): LongInt; Повертає кількість записів у файлі. Наприклад, Seek (f, FileSize (f)) встановить покажчик у кінець файлу (після останнього запису). Procedure Truncate (f: File of Type); Знищує (відрубує) кінець файлу починається із запису, на яку встановлено вказівник. 17.4. Файли без типу Файл складається з компонент однакового розміру. Тип даних не має значення. Доступ до даних здійснюється через файлову змінну. Як і у файлах з типом, в такому файлі допустимо прямий доступ до будь-якого запису, причому в рамках відкритого файлу припустиме як писати, так і читати записи. Файлова змінна може бути оголошена так: Var F: File; Після кожного читання або виведення запису покажчик автоматично встановлюється на наступний запис. Відсутність типу запису дозволяє виконувати обробку файлів різних типів за допомогою універсальних процедур і функцій. 17.4.1. Процедури і функції для роботи з файлом без типу Procedure AssignFile (f: File; FileName: String); Пов'язує файлову змінну f з дисковим файлом FileName. Procedure Rewrite (f: File); Створює новий файл і відкриває його. Якщо файл існує, то він знищується і створюється як новий. Procedure Reset (f: File [; Size: Word]); Відкриває існуючий файл і встановлює вказівник на перший запис. За відсутності файлу виникає помилка вводу / виводу. Параметр Size вказує розмір запису файлу, що відкривається. При його відсутності розмір запису за замовчуванням дорівнює 1. Procedure BlockRead (f: File; Var Buf; Count: Word [; Var Result: Word]); Читає з файлу Count записів в змінну Buf. Result - реально прочитане кількість записів. Procedure BlockWrite (f: File; Var Buf; Count: Word [; Var Result: Word]); Пише в файл першого Count записів з змінної Buf. Result - реально записане кількість записів. Procedure Seek (f: File; N: LongInt); Переміщає покажчик на запис з номером N. Перший запис має порядковий номер 0. Functio n FilePos (f: File): LongInt; Повертає номер запису, на яку встановлено вказівник. Procedure CloseFile (f: File); Закриває файл. Function Eof (f: File): boolean; Повертає True, якщо досягнуто кінець файлу. Function FileSize (f: File): LongInt; Повертає кількість записів у файлі. Наприклад, Seek (f, FileSize (f)) встановить покажчик у кінець файлу (після останнього запису). Procedure Truncate (f: File of Type); Знищує (відрубує) кінець файлу починається із запису, на яку встановлено вказівник. Мова Object Pascal не накладає ніяких обмежень на довжину запису (теоретично вона може мати розмір до 2 Гб). Приклад опису та звернення до функції ReadFromFile, читаючої з файлу nF в позиції Pos запис r розміром Sz. function ReadFromFile (nF: String; Pos: Word; Var r; Sz: Word): boolean; Var g: File; Recs, ReadReal: Integer; RecRead: boolean; Begin Assign (g, nF); Recs: = FileSize (g) div Sz; {кількість записів у файлі} RecRead: = (Pos <Recs); {запис з номером Pos є?} if RecRead then begin {якщо запис є} Reset (g, Sz); {відкрити файл} try Seek (g, Pos); {встановити покажчик на запис} BlockRead (g, r, 1, ReadReal); {прочитати запис} RecRead: = (ReadReal = 1); {прочитано успішно?} finally Close (g); {закрити файл} end; end; Result: = RecRead; end {ReadFromFile}; ... Type tStud = Record Fio: String [60]; Curs: byte; Stipendiya, Room: boolean; End; Var Stud: tStud; ... if ReadFromFile ('base2.ff1', 12, Stud, SizeOf (Stud)) then Writeln ('Запис з 12-ї позиції прочитана'); Наведемо ще приклад. У директорії 'c: BasesSdudBase' знаходиться файл 'AllStuds.bs', в якому зберігаються дані про студентів у вигляді записів типу Type TStud = Record {студент} Fio: String [50]; {'Прізвище Ім'я По батькові'} Born: byte; {Рік народження, наприклад, 1979} Faculty: String [4]; {Факультет, наприклад, 'МТФ'} Group: String [8]; {Група, наприклад, 'МТ 17-2'} End; Нижче наведена універсальна процедура, яка копіює з цього файлу в інший файл дані тільки про тих студентів, які мають заданий рік народження: Procedure StudsCopy (nF1, nF2: ShortString; BornYear: byte; Var Count: Word; Var: Ind: ShortInt); {NF1 - файл-джерело, nF2 - файл-приймач, BornYear - необхідний рік народження, Count - скопійовано записів, Ind - індикатор контролю: 0 - нормально, 1 - було невірне читання, була невірна запис} Var g: tStud; K, Sz, i, j: Word; f1, f2: File; Begin Count: = 0; {ініціалізація лічильника} Ind: = 0; {спочатку припускаємо нормальний процес, інакше Ind змінимо} Sz: = SizeOf (g); {розмір одного запису} K: = KdnFileSize (nF1, Sz); {кількість записів у файлі-джерелі} If (K> 0) then {якщо у файлі-джерелі є записи} Begin Assign (f1, nF1); {файл-джерело пов'язуємо змінної f1} Reset (f, Sz); {відкриваємо файл-джерело з записами розміру Sz} Assign (f2, nF2); {файл-приймач пов'язуємо змінної f2} Rewrite (f2, Sz); {створюємо новий файл-приймач під записи розміру Sz} try For j: = 1 to K do Begin BlockRead (f1, g, 1, i); {читання запису} Case i of 1: {запис прочитана} if (g.Born = BornYear) then {студент має необхідний рік народження} begin BlockWrite (f2, g, 1, i); {запис у файл-приймач} If (i> 0) then Inc (Count) {якщо записано правильно} else begin Ind: = 1; Break; End; {записано невірно, відразу вихід з циклу} end; {if} 0: begin Ind: = -1; Break; end; {запис не прочитана, відразу вихід з циклу} end; {Case} end; {циклу For} finally CloseFile (f1); {закриваємо файл-джерело} CloseFile (f2); {закриваємо файл-приймач} end; {блоку try - finally - end} End {If}; End {StudsCopy}; Оператори, що реалізують копіювання необхідних даних у файл '1979. Bs ': StudsCopy ('AllStuds.bs', '1979. Bs ', 1979, Count1979, Ind1979); Case Ind1979 of -1: Writeln ('Зафіксована помилка читання'); 1: Writeln ('Зафіксована помилка запису'); 0: Writeln ('Процес пройшов нормально'); end; {Case} Writeln ('скопійовано записів:' + IntToStr (Count1979)); У цьому прикладі використана зовнішня процедура KdnFileSize {кількість записів у файлі}. Наведемо її текст: function KdnFileSize (nF: ShortString, Siz: Word): LongInt; {NF - ім'я файлу, Siz - розмір одного запису} Var F: File; L: LongInt; Begin L: = 0; If FileExists (nF) then begin Assign (f, nF); Reset (f, 1); L: = SizeOf (f); If not (L mod Siz = 0) then Writeln ('Файл' + nF + має інший тип '); L: = L div Siz; CloseFile (f); End; Result: = L; End; 17.5. Процедури і функції для роботи з файлами Ці підпрограми призначені для роботи з файлами, папками (директоріями) та дисками. Procedure ChDir (Dir: String); Робить папку Dir поточної. Приклад: ChDir ('c:'); Procedure GetDir (D: Byte; Var Dir: String); Повертає поточну папку на заданому пристрої. (D = 0 - поточний диск, 1 - диск А, 2 - диск B і т.д.). Приклад: GetDir (0, s); Procedure RmDir (Dir: String); Знищує задану теку. Папка не повинна містити вкладених папок або файлів. Приклад: RmDir ('Folder66'); Procedure Erase (f); Видаляє файл, пов'язаний з файлової змінної f. Файл повинен бути закритий. Procedure Rename (f, FileName: String); Перейменовує файл, пов'язаний з файлової змінної f. Файл повинен бути закритий. Приклад: Rename (g, 'studs.txt'); Function DiskFree (D: byte): LongInt; Повертає кількість вільної пам'яті в байтах на пристрої D. Код драйвера задається так само, як у процедурі GetDir. Якщо код вказаний невірно, то повертає -1. Function DiskSize (D: byte): LongInt; Повертає кількість вільної пам'яті в байтах на пристрої D. Код драйвера задається так само, як у процедурі GetDir. Якщо код вказаний невірно, то повертає -1. Function FindFirst (const Path: string; Attr: Integer; var F: TSearchRec): Integer; Знаходить ім'я першого файлу з заданими атрибутами Attr в папці Path. Результат пошуку виводить в змінну F. Якщо пошук успішний, то функція поверне 0, інакше поверне код помилки Widows. До FindFirst можна звертатися не тільки як до функції, але і як до процедури. Атрибути файлу наведено в табл. 17. Таблиця 17 Атрибут | Опис файлів | faReadOnly faHidden faSysFile faVolumeID faDirectory faArchive faAnyFile | Файли "Тільки для читання" Приховані файли Системні файли Файл ID-значень Папки (директорії) Архіви (файли) Всі файли |
Тип, що характеризує знайдений файл, представляє запис виду: type TSearchRec = Record Time: Integer; {час} Size: Integer; {розмір файлу в байтах} Attr: Integer; {атрибути файлу} Name: TFileName; {DOS-шлях до файлу} ExcludeAttr: Integer; FindHandle: THandle; FindData: TWin32FindData; {додаткова інформація про фото} end; Приклад: Var SR: TSearchRec; S: String; ... FindFirst ('c: Program Filesdelphi4bin *.*', faAnyFile, SR); if (SR.Attr = faArchive) then S: = 'Файл' + SR.Name + 'має розмір' + IntToStr (SR.Size) + 'байт'; У даному прикладі процедура FindFirst шукає перший файл за маскою'*.*' (всі файли) у папці 'c: Program Filesdelphi4bin'. Атрибут faAnyFile означає, що пошук здійснюється за всіма видами файлів, під якими розуміються папки (директорії), '.', '..' - Посилання на поточну і батьківську папку, внутрішні папки і власне файли. Останні в термінології файлової атрибутики називаються архівами. Далі, якщо знайдений файл є архів, т е. файл в загальноприйнятій термінології, то в рядок S буде надруковано повідомлення. Наприклад, якщо знайдений файл має ім'я Ig.ttg і його розмір дорівнює 15899, то S = 'Файл Ig.ttg має розмір 15889 байтів'. Function FindNext (var F: TSearchRec): Integer; Знаходить наступний файл, атрибути якого вказані у FindFirst. Procedure FindClose (var F: TSearchRec); Закриває дію FindFirst / FindNext. Function DeleteFile (const FileName: string): Boolean; Видаляє файл по імені. Якщо файл не може бути видалений або не існує - повертає False. |
Function CreateDir (const Dir: string): Boolean;
Створює нову папку.
Function GetCurrentDir: string;
Повертає поточну папку.
Function GetCurrentDir: string;
Повертає поточну папку.
Function SetCurrentDir (const Dir: string): Boolean;
Установка нової поточної папки.
Function RemoveDir (const Dir: string): Boolean;
Видалення папки. Перед видаленням папка повинна бути порожньою.
Function ExtractFileDir (const FileName: string): string;
Виділяє з повного імені файлу FileName папку, в якій міститься це файл.
Function ExtractFilePath (const FileName: string): string;
Виділяє з повного імені файлу FileName шлях до файлу.
Function ExtractFileExt (const FileName: string): string;
Повертає розширення файлу FileName.
Function ExtractFileName (const FileName: string): string;
Повертає ім'я файлу FileName (без розширення).
Function DirectoryExists (Dir: string): boolean;
Перевіряє існування директорії. Приклад:
if DirectoryExists ('C: APPSSALESLOCAL') then; Function FileExists (FileName: string): boolean;
Перевіряє наявність файлу. Приклади:
B: = FileExists ('C: APPSSALESLOCALFort.pas'); {повне ім'я}
B: = FileExists ('Fort.pas'); {зазначено усічене ім'я файлу, перевірка його існування лише в поточній директорії}
Procedure ForceDirectories (Dir: string);
Створює нову директорію.
Procedure ForceDirectories (C: APPSSALESLOCAL).
П р и м і т а н і е. До моменту звернення до процедури директорії APPS і SALES повинні існувати.
Приклад процедури видалення даних з поточної директорії, включаючи файли і вкладені папки.
Procedure DelInsideDir (FullDir: tPathStr);
Var
L: Integer;
Sr: TSearchRec;
dr, q: tPathStr;
begin
if ExistDir (FullDir) then {така директорія є}
begin
GetDir (0, dr); {запам'ятати поточну директорію}
ChDir (FullDir); {поточної стає видаляється директорія}
L: = FindFirst (Slash (FullDir )+'*.*', faAnyFile, Sr); {пошук першого файлу}
try
While (L = 0) do begin {поки файли знаходяться}
Case Sr.Attr of
faDirectory: {знайдений файл - внутрішня директорія}
if (Sr.Name '.') and (Sr.Name'..') then {це не посилання, директорія}
begin
{Видалення внутрішнього вмісту директорії}
DelInsideDir (Slash (FullDir) + Sr.Name);
q: = Slash (FullDir) + Sr.Name;
ChDir (ExtractFilePath (q));
{Видалення самої директорії (можна, тому що вона тепер порожня)}
if NotEmpStr (ExtractFileName (q)) then RmDir (ExtractFileName (q));
end;
faArchive: DeleteFile (Sr.Name); {це файл, віддаляється}
end; {Кінець Case-оператора}
L: = FindNext (Sr); {Наступне фото директорії}
end; {циклу While}
finally
FindClose (Sr); {закрити пошук файлів}
end; {try - finally - end}
ChDir (dr); {повернутися в поточну директорію}
end; {if}
end; {процедури}
Наприклад, якщо необхідно стерти дані з дискети, то це можна зробити за допомогою оператора: DelInsideDir ('A:');
18. Класи і об'єкти
У Object Pascal класами називаються спеціальні типи, які містять поля, методи і властивості. Попередником класу є застарілий нині тип мови Turbo Pascal, званий об'єктом. Об'єкт був введений в Turbo Pascal до створення Delphi. З появою Delphi в новій версії мови Object Pascal об'єкти, для сумісності зі старим програмним продуктом, збережені. Однак нині використання об'єктів не актуально.
Клас є покажчик. Однак на відміну від традиційних покажчиків це покажчик особливого типу: у ньому не можна використовувати символ "^" при зверненні до класу.
18.1. Інкаспуляція, успадкування і поліморфізм
Клас, об'єднуючи в собі поля, методи і властивості в єдине ціле, є закінченою структурною одиницею, призначеної для вирішення окремого завдання. Зазвичай таким завданням є завдання дозволу деякого кола супутніх проблем. Так, клас TRichEdit представляє собою потужний текстовий редактор rtf-файлів (файлів у форматі Rich Text Format), який призначений для організації перегляду і редагування файлу, збереження і зміни розмірів і типів шрифтів, пошуку рядків символів і багато чого іншого. Таке об'єднання полів, методів і властивостей в єдине ціле називається інкаспуляціей.
У мові існує безліч класів (близько 300), які створені розробниками мови Object Pascal - співробітниками фірми Inprise International - для програмістів, що використовують середу Delphi. Такі класи можна назвати фірмовими.
Програміст, складаючи програму, завжди створює свої власні класи. Ці класи створюються або неявно, коли програміст конструює програму візуальними засобами Delphi, а текст класів при цьому становить сама Delphi, або явно, коли програміст пише код класу засобами мови Object Pascal.
Новий клас будується на основі іншого, простішого, класу. Для цього в заголовку класу вказується його клас-батько. Синтаксис заголовка нового класу має вигляд
type className = class (ancestorClass)
Тут className - ім'я нового класу; ancestorClass - ім'я класу-батька. Новий клас автоматично успадковує поля, методи і властивості свого батька і може поповнитися своїми полями, методами і властивостями. Це властивість класів називається спадкуванням. Можливість успадкування дозволяє, дотримуючись методу від простого до складного, створювати класи який завгодно ступеня складності. Найпростішим класом є клас TObject, який не містить полів і властивостей, проте має деякий безліч методів, які забезпечують створення, знищення та обслуговування цього класу і необхідних для нормального функціонування програми. Саме на основі цього спільного для всіх класів прабатька будується дерево спадкування класів. Наприклад:
type TPersistent = class (TObject),
type TComponent = class (TPersistent),
type TControl = class (TComponent).
Нерідко методи, описані у класі-батьку, виявляються з яких-небудь причин незадовільними для класу-нащадка. У цьому випадку в класі-нащадку можна створити метод з тим же ім'ям, що і в класі-батьку. При цьому виявиться, що в обох класах будуть діяти різні методи з одним і тим же ім'ям. Поліморфізм і є така властивість споріднених класів, яке полягає в допустимості оголошення в них однойменних методів.
18.2. Синтаксис класу
Синтаксис всякого класу має вигляд
type className = class (ancestorClass)
memberList
end;
Тут className - ім'я класу; class - ключове слово; ancestorClass - тип класу-батька; memberList - список полів, методів і властивостей. Нижче наведено текст модуля main, що містить клас TForm1.
unit main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;
type
TForm1 = class (TForm) {оголошення класу TForm1}
Button1: TButton; {полі}
L1: TLabel; {полі}
L2: TLabel; {полі}
Button2: TButton; {полі}
procedure Button1Click (Sender: TObject); {метод}
procedure FormActivate (Sender: TObject); {метод}
end;
Var i: Integer;
implementation
{$ R *. DFM}
procedure TForm1.Button1Click (Sender: TObject); {опис методу}
begin
L1.Caption: = DateTimeToStr (Date);
L2.Caption: = TimeToStr (Time);
end;
procedure TForm1.FormActivate (Sender: TObject); {опис методу}
begin
i: = 125;
end;
end.
18.3. Поля класу
Полем може бути будь-який інкаспулірованний в клас тип або інший клас, наприклад:
type
TKdnClass = class (TObject)
i, j: integer;
s: String;
TKdn1: TKdn0;
End;
Якщо нащадком є TObject, то в заголовку його можна опустити.
Клас-нащадок має доступ до всіх полів своїх предків, але не може їх перевизначати, тому що він стане недоступний. Приклад:
type
TPredok = class {оголошення класу-предка}
Value: Integer;
end;
TPotomok = class (TPredok) {оголошення класу-нащадка}
Value: string; {перекриття успадкованого поля}
end;
var
My1: TPredok; {оголошення змінної класу}
My2: TPotomok; {оголошення змінної-класу}
begin
My1: = TPotomok.Create; {створює клас типу TPredok!}
My2: = TPotomok.Create; {створює клас типу TPotomok}
My1.Value: = 'Hello!'; {Помилка, не той тип поля TPredok}
My2.Value: = 'Hello!'; {Правильно, працює поле Value: String}
My2.Value: = 8; {помилка: поле Value: Integer перекрито}
end;
У цьому прикладі описано два класи: TPredok - предок і TPotomok - нащадок. Кожен з класів містить однойменні поля Value різних типів.
Далі в var-секції оголошені дві різні змінні My1 і My2 типу class. На перший погляд може здатися, що оператор-конструктор об'єкта My1: = TPotomok.Create створить об'єкт My1 (виділить під нього пам'ять) типу TPotomok. Однак це не так, оскільки My1 має інший тип. З цієї причини конструктор створить об'єкт батьківського типу, тобто об'єкт типу TPredok. Тепер стає зрозуміле джерело помилок, які мають місце в кількох операторах наведеного прикладу.
18.4. Методи класу
Методом класу є інкаспулірованная процедура або функція. Ці подрограмми оголошуються так само, як звичайні підпрограми. Метод повинен бути оголошений в описі класу у вигляді окремого заголовка, а код методу - описаний в секції implementation із зазначенням через символ "." приналежності методу до свого класу, наприклад:
type
TMyClass = class (TObject) {оголошення класу}
...
procedure DoSomething; {оголошення методу DoSomething}
...
end;
Опис для DoSomething має бути наведено пізніше в секції implementation модуля:
procedure TMyClass.DoSomething; {вигляд заголовка класс.метод}
begin
...
end;
При зверненні до методу можливе використання складеного імені або оператора With, наприклад:
Var KdnClass: TKdnClass;
...
KdnClass.MyProc1; / / два приклади звернення до методів
X: = KdnClass.MyFunc2; / / за допомогою складових імен
...
With KdnClass do / / ті ж звернення
Begin / / за допомогою оператора With
MyProc1;
X: = MyFunc2;
End;
Однойменні методи можуть перекриватися в нащадках точно так, як це показано у прикладі перекриття полів. Таке перекриття називається статичним.
Для розширення можливостей частіше використовується динамічне перекриття. Для цього батьківський метод повинен мати директиву dinamic (динамічний метод) або virtual (віртуальний метод), а перекриває метод - директиву override. Приклад:
type
TFigure = class
procedure Draw; virtual; {віртуальний метод}
end;
TRectangle = class (TFigure)
procedure Draw; override; {перекриває метод}
end;
TEllipse = class (TFigure)
procedure Draw; override; {перекриває метод}
end;
У цьому прикладі оголошений віртуальний метод Draw батьківського класу TFigure і два однойменних методу в класах-нащадках TRectangle і TEllipse. Останні оголошені перекривають (override).
Таке оголошення дозволяє перекривати методи з метою досягнення потрібних цілей:
var
Figure: TFigure;
begin
Figure: = TRectangle.Create; / / створення класу
Figure.Draw; / / виклик TRectangle.Draw
Figure.Destroy; / / знищення класу
Figure: = TEllipse.Create; / / створення класу
Figure.Draw; / / виклик TEllipse.Draw
Figure.Destroy; / / знищення класу
end;
Семантично віртуальний і динамічний методи працюють однаково. Різниця полягає в тому, що віртуальний метод оптимізує швидкість обчислень, а динамічний метод оптимізує розмір відповідного програмного коду.
У класі метод може бути оголошений абстрактним за допомогою директиви adstract. Такий метод є віртуальним або динамічним, проте, на відміну від інших методів, може не мати в секції implementation свого коду. Клас, що має абстрактні методи, називається абстрактним. Такі класи і методи можуть нічого не робити, інкаспуліруя таким способом доступ до методів нащадків, наприклад:
procedure DoSomething; virtual; abstract;
Звернення до пеперекривається абстрактного методу викликає помилку часу виконання (run time error), наприклад:
Type
TClass2 = class (TClass0)
...
procedure Paint; virtual; abstract;
end;
TClass1 = class (TClass0)
...
procedure Paint; override;
end;
var
jClass1: TClass1;
jClass2: TClass2;
begin
jClass1.Paint; / / правильно
jClass2.Paint; / / неправильно: звернення до абстрактного методу
...
end;
Кожен клас має дві особливі методу - конструктор і деструктор. Конструктор призначений для створення класу, тобто для виділення під нього динамічної пам'яті. Деструктор, навпаки, призначений для знищення класу, тобто для звільнення ділянки пам'яті, зайнятого цим класом. У класі TObject є стандартні методи Create (створити) і Destroy (знищити). У цьому класі оголошений також метод Free, котрий спочатку перевіряє коректність адреси і тільки потім викликає метод Destroy. У зв'язку з цим краще використовувати метод Free замість методу Destroy. Кожен клас за замовчуванням містить змінну Self, в яку після виділення динамічній пам'яті поміщається адреса класу. Перш ніж виконати звернення до методів класу, його потрібно створити. Хоча конструктор і деструктор є процедурами, вони оголошуються спеціальними словами. Конструктор оголошується словом Constructor, деструктор - словом Destructor. Часто для забезпечення доступу до полів предка в конструкторі необхідно попередньо створити клас-предок. Це можна зробити c допомогою слова Inherited.
Приклад:
type
TShape = class (TGraphicControl)
Private {внутрішні оголошення}
FPen: TPen;
FBrush: TBrush;
procedure PenChanged (Sender: TObject);
procedure BrushChanged (Sender: TObject);
public {зовнішні оголошення}
constructor Create (Owner: TComponent); override;
destructor Destroy; override;
...
end;
constructor TShape.Create (Owner: TComponent);
begin
inherited Create (Owner); / / створення класу-предка TGraphicControl
Width: = 65; / / зміна успадкованих властивостей TGraphicControl
Height: = 65;
FPen: = TPen.Create; / / створення окремого поля TPen типу class
FPen.OnChange: = PenChanged;
FBrush: = TBrush.Create; / / створення окремого поля TBrush типу class
FBrush.OnChange: = BrushChanged;
end;
Деякі прості класи можуть бути створені й знищені без оголошення конструкторів і деструкторів. Наприклад, якщо клас є нащадком TObject, то в ньому явно Constructor і Destructor в деяких випадках оголошувати немає потреби:
Type TClassy = class;
..
var Classy: TClassy;
...
Classy: = TClassy.Create; {створення класу}
...
Classy: = TClassy.Free; {знищення класу}
У мові є можливість оголошувати в межах одного класу кілька методів з одним і тим же ім'ям. При цьому всякий такий метод повинен бути перезавантажуємо (директива overload). Компілятор такі методи ідентифікує по своїм унікальним набором формальних параметрів. Для того, щоб відмінити реакцію компілятора Delphi на появу методу з тим же ім'ям, кожен такий метод потрібно позначити директивою reintroduce. Далі в секції implementation необхідно привести коди всіх таких методів.
Приклад:
Type TClassy = class;
Procedure HH (i, j: byte; var s: String); reintroduce; overload;
Procedure HH (q: String); reintroduce; overload;
Procedure HH (a: array oh Integer); reintroduce; overload;
...
implementation
...
Procedure TClassy.HH (i, j: byte; var s: String);
Begin
S: = IntToStr (i + j);
End;
Procedure TClassy.HH (q: String);
Begin
L2.Cattion: = q;
End;
Procedure TClassy.HH (a: array oh Integer);
Begin
L1.Cattion: = IntToStr (a [6] + a [4]);
End;
...
Тепер, після звернення до методу по імені TClassy.HH, програма викличе саме той метод, формальні параметри якого відповідають фактичним параметрам у зверненні.
18.5. Властивості класу
Властивості, як і поля, є атрибутами класу. Властивості оголошуються за допомогою слів property, read і write. Слова read і write конкретизують призначення властивості. Синтаксис властивості такий:
property propertyName [indexes]: type index integerConstant specifiers;
де propertyName - ім'я властивості; [indexes] - параметри-імена у формі імя1, імя2, ... , ІмяN: type; index - ціла константа; read, write, stored, default (або nodefault) і implements - специфікації. Будь-яке оголошення властивості повинна мати одну з специфікацій read або write або обидві разом.
Приклади:
property Objects [Index: Integer]: TObject read GetObject write SetObject;
property Pixels [X, Y: Integer]: TColor read GetPixel write SetPixel;
property Values [const Name: string]: string read GetValue write SetValue;
property ErrorCount: Integer read GetErrorCount;
property NativeError: Longint read FNativeError;
Неіндексовані властивості схожі на звичайні поля, а індексовані властивості нагадують поля-масиви. У програмі властивості поводяться майже так само, як звичайні поля. Різниця в тому, що властивість має більш відповідальне призначення. Наприклад, воно може активізувати деякі методи для додання об'єктам необхідного властивості. Так якщо змінено властивість шрифту будь-якого візуального класу, то зміна властивості шрифту спричинить за собою перемальовування тексту та виконання низки супутніх операцій, які забезпечать класу саме таку властивість.
Кожна властивість може мати специфікацію read або write або обидва разом у формі
read fieldOrMethod
write fieldOrMethod
де fieldOrMethod - ім'я поля або методу, оголошеного в класі, або властивість класу-предка.
Якщо fieldOrMethod оголошено в класі, то воно повинно бути визначено в тому ж класі. Якщо воно оголошено в класі-предка, то воно повинно бути певне з нащадка, тобто не повинно бути приватним полем або методом класу-предка. Якщо властивість є поле, то воно повинно мати тип. Якщо fieldOrMethod є read-специфікація, то воно повинно бути функцією без параметрів, тип якої збігається з типом властивості. Якщо fieldOrMethod є write-специфікація і метод, то воно повинно бути процедурою, що повертає просте значення або константу того ж типу, що тип властивості. Наприклад, якщо властивість оголошено:
property Color: TColor read GetColor write SetColor;
тоді метод GetColor повинен бути описаний як
function GetColor: TColor;
і метод SetColor повинен бути описаний як
procedure SetColor (Value: TColor);
або
procedure SetColor (const Value: TColor);
Якщо властивість має специфікацію read, то воно має атрибут "read only" (тільки для читання). Якщо властивість має специфікацію write, то воно має атрибут "write only" (тільки для читання).
18.6. Структура класу
Кожен клас має структуру, яка складається із секцій. Кожна секція оголошується спеціальним зарезервованим словом. До їх числа належать: published (декларовані), private (приватні), protected (захищені), public (доступні), automated (автоматизовані). Усередині кожної секції спочатку оголошуються поля, потім - властивості і методи.
Приклад:
type
TMyClass = class (TControl)
private
... {Приватні оголошення тут}
protected
... {Захищені оголошення тут}
public
... {Доступні оголошення тут}
published
... {Декларовані оголошення тут}
end;
Секції визначають області видимості компонент класу:
Private - компоненти класу доступні тільки усередині цього класу;
Public - компоненти класу доступні в поточному і будь-якому іншому модулі, який містить посилання у списку uses на модуль, в якому оголошено клас;
Published - те ж, що Public, однак у ній повинні бути перераховані властивості, які доступні не тільки на етапі виконання програми, але і на етапі її візуального конструювання засобами Delphi;
Protected - Секції доступна тільки методам поточного класу і методам класів-предків;
Automated - секція використовується для оголошення властивостей і методів обробки OLE-контейнерів в рамках OLE-технології.
Порядок проходження секцій довільний. Будь-яка із секцій може бути як порожній, так і оголошена кілька разів в рамках одного класу.
18.7. Операції над класами
Над класами дозволено виконувати дві операції - is і as.
1. Операція is. Синтаксис вираження, що містить операцію is, має вигляд
object is class
Цей вираз має логічний тип (boolean) і повертає True, якщо змінна object має тип class класу, інакше - False.
Приклад:
if ActiveControl is TEdit then TEdit (ActiveControl). SelectAll;
У цьому прикладі: якщо клас ActiveControl має тип TEdit, то буде виконаний метод TEdit (ActiveControl). SelectAll.
2. Операція as. Синтаксис вираження, що містить операцію as:
object as class
Результатом обчислення цього виразу є посилання на об'єкт того ж типу, що й тип класу class. При виконанні програми object може мати той же тип, або тип класу-нащадка, або nil.
Приклади:
with Sender as TButton do / / якщо Sender має тип TButton
begin / / або тип-нащадок від TButton
Caption: = '& Ok';
OnClick: = OkClick;
end;
(Sender as TButton). Caption: = '& Ok'; / / властивості Caption змінної
/ / Sender типу TButton або його нащадка присвоюється значення '& Ok'
Додаток
Перелік
налагоджених процедур і функцій,
написаних автором
Нижче використані глобальні типи і змінні:
Type
CompareType = (Less, Equal, Greater);
Var
Lon, Lon2: LongInt;
Serv: String [255];
Procedure Delay (MilliSec: LongInt);
{Затримка часу на MilliSec мілісекунд}
Var k: LongInt;
begin
k: = GetTickCount; {в модулі Windows.pas}
While GetTickCountj) then j: = i;
i: = Length (s3);
if (i> j) then j: = i;
i: = Length (s4);
if (i> j) then j: = i;
Warn1 (Center (s1, j )+''# 13 # 10 +''+ Center (s2, j)
+''# 13 # 10''+ Center (s3, j )+''# 13 # 10 +''+ Center (s4, j));
end;
Function DaNet (S: String): boolean;
{Вікно. Призначено для питання, на яке можна відповісти, клацнувши по одній з кнопок "Так" або "Ні"}
begin
DaNet: = MessageDlg (S, mtConfirmation, [mbYes, mbNo], 0) = mrYes;
Screen.ActiveForm.Refresh;
end;
Function DaNet4 (s1, s2, s3, s4: String): boolean;
{Вікно. Те ж, що DaNet, тільки в 4 рядки}
begin
DaNet4: = MessageDlg (Trim (s1 )+''# 13 # 10 +''+ Trim (s2 )+''# 13 # 10''+ Trim (s3)
+''# 13 # 10 +''+ Trim (s4), mtConfirmation, [mbYes, mbNo], 0) = mrYes;
Screen.ActiveForm.Refresh;
end;
Function InOtrReal (i, a, b: real): boolean;
{Якщо i в орезке [a, b], то повертає True}
begin
Result: = (i> = a) and (i 0) and (StartPos = Lon);
end;
Function ChStr (Ch: Char; d: Word): String;
{Створює рядок з символу Ch, повтореного d раз}
begin
if d> 0 then
begin
SetLength (Result, d);
FillChar (Result [1], d, Ch);
end;
end;
Function Prop (d: Word): String;
{Створює рядок з d прогалин}
begin
Result: = ChStr ('', d);
end;
Function Pad (s: String; d: Word): String;
{Вставляє праворуч від рядка прогалини, добираючи її до довжини d}
begin
Serv: = s;
Lon: = Length (s);
If (d> Lon) then Serv: = s + Prop (d-Lon);
Result: = Serv;
end;
Function PadCopy (s: String; n, d: Word): String;
{Копіює з s починаючи з позиції n рядок довжини d. У разі меншої рядка добирає її до довжини d}
begin
Serv: = Copy (s, n, d);
if Length (Serv) <d then Serv: = Pad (Serv, d);
Result: = Serv;
end;
Function LeftPad (s: String; d: Word): String;
{Вставляє ліворуч від рядка прогалини, добираючи її до довжини d}
begin
Serv: = s;
Lon: = Length (s);
if (d> Lon) then Serv: = Prop (d-Lon) + s;
Result: = Serv;
end;
Function Center (s: String; d: Word): String;
{Вставляє ліворуч і праворуч від рядка порівну прогалини, добираючи її до довжини d}
begin
Serv: = s;
Lon: = Length (s);
Lon2: = Round (0.5 * (d-Lon));
if (d> Lon) then Serv: = Prop (Lon2) + s + Prop (d-Lon2);
Result: = Serv;
end;
Functio n CompStrings (s1, s2: String): CompareType;
{Порівняння рядків: s1s2 - Greater}
begin
if (s1s2) then CompStrings: = Greater
else
CompStrings: = Equal;
end;
Function CompReal (r1, r2: Real): CompareType;
{Порівняння дійсних чисел}
begin
if (r1r2) then Result: = Greater
else
Result: = Equal;
end;
Procedure IncRe (Var r: Real; h: real);
begin
r: = r + h;
end;
Function LongToStr (L: LongInt; d: byte): String;
{Конвертує ціле в рядок довжини d}
begin
Str (L, Serv);
Result: = LPad (Serv, d);
end;
Function Long2Str (L: LongInt): String;
{Конвертує ціле в рядок}
begin
Str (L, Serv);
Result: = Serv;
end;
Function StrLong (st: String): LongInt;
{Конвертує рядок в ціле}
begin
Val (Trim (st), Lon, Code);
Result: = Lon; end;
Function Str2Long (st: String; Var L: LongInt): boolean;
{Конвертує рядок в ціле. Повертає True у разі успіху}
begin
Val (Trim (st), L, Code);
Result: = (Code = 0);
end;
Function RealToStr (R: Real; Posle: byte): String;
{Конвертує Real в рядок, Posle - кількість символів в дробової частини R}
begin
Str (R: 20: Posle, Serv);
RealToStr: = Trim (Serv);
end;
Function Slash (Dir: String): String;
{Ставить в кінець шляху символ''}
begin
Serv: = Trim (Dir);
if (Serv [Length (Serv )]'') then Result: = Serv +''
else Result: = Serv;
end;
Function ChWinDos (Ch: Char): Char;
{Перетворює російська Windows-символ у російську DOS-символ}
Var i, j: byte;
begin
i: = Ord (Ch);
Case i of
168: {Е} j: = 240;
184: {е} j: = 241;
192 .. 255: if (i> 239) then j: = i-16 else j: = i-64
else j: = i;
end;
Result: = Char (j);
end;
Function ChDosWin (Ch: Char): Char;
{Перетворює російська DOS-символ у російський Windows-символ}
Var i, j: byte;
begin
i: = Ord (Ch);
Case i of
240: {Е} j: = 168;
241: {е} j: = 184;
128 .. 175: j: = i +64;
224 .. 239: j: = i +16
else j: = i;
end;
Result: = Char (j);
end;
Function StrWinDos (st: String): String;
{Перетворює російську Windows-рядок у російську DOS-рядок}
Var
n, i: byte;
s: ^ String;
begin
New (s);
n: = Length (st);
s ^: ='';
if (n> 0) then
for i: = 1 to n do
s ^: = s ^ + ChWinDos (st [i]);
Result: = s ^;
Dispose (s);
end;
Function StrDosWin (s: String): String;
{Перетворює російську DOS-рядок у російську Windows-рядок}
Var
n, i: byte;
s: ^ String;
begin
New (s);
n: = Length (st);
s ^: ='';
if (n> 0) then
for i: = 1 to n do
s ^: = s ^ + ChDosWin (st [i]);
Result: = s ^;
end;
Functio n InputStr (const Prompt: String; Var s: String; IsParol: byte): boolean;
{Введення рядка. Prompt - пояснення, s - вводиться рядок,
isParol = 1, якщо засекречений введення, інакше видимий}
begin
Result: =
KdnInputQuery ('Введення рядка', Prompt, s, clBlack, (IsParol = 1));
end;
Function ParolControl (RealParol: String): boolean;
{Повертає True, якщо введена рядок збігається з RealParol}
var
b, h: boolean;
i: byte;
begin
St :='';
i: = 0;
b: = false;
Repeat
Inc (i);
h: = InputStr ('Введіть пароль ...', St, 1);
if h then b: = (St = RealParol);
if not b and h then Warn1 ('Помилка');
Until b or (i = 3) or (not h);
Result: = b;
end;
Function ExistSubDir (SubDir: String; Dir: tPathStr): boolean;
{Встановлює наявність субдіректоріі SubDir усередині директорії Dir. Наприклад, в D: DIR0001 субдіректоріі BAR}
begin
Result: = DirectoryExists (Slash (SubDir) + Dir);
end;
Function GetFileSize (const FileName: string): LongInt;
{Розмір файлу}
var Sr: TSearchRec;
begin
if FindFirst (ExpandFileName (FileName), faAnyFile, Sr) = 0 then
Result: = Sr.Size
else Result: = -1;
end;
Function FileDateTime (const FileName: string): System.TDateTime;
{Час створення файлу FileName, наприклад:
s: = DateTimeToStr (FileDateTime ('c: KdnBreadBread.exe'))}
begin
Result: = FileDateToDateTime (FileAge (FileName));
end;
Function HasAttr (const FileName: string; Attr: Word): Boolean;
{Чи має файл FileName атрибут Attr}
begin
Result: = (FileGetAttr (FileName) and Attr) = Attr;
end;
Procedure AppendText (Var f: Text; nF: String);
{Відкриває текстовий файл для додавання рядків}
begin
Assign (f, nF);
if KdnFS (nF, 1)> 0 then Append (f) else Rewrite (f);
end;
Procedure AppendToText (nF, s: String);
{Додає рядок у кінець текстового файлу}
Var f: TextFile;
begin
AppendText (f, nF);
Writeln (f, s);
CloseFile (f);
end;
Procedure KdnExec (Command: String);
{Запуск іншої програми, наприклад 'c: KdnBreadDirKdnBread.exe'}
begin
Serv: = Command + # 0;
If WinExec (@ Serv [1], SW_SHOWNORMAL
Додати в блог або на сайт
Цей текст може містити помилки.
Програмування, комп'ютери, інформатика і кібернетика | Реферат
285.6кб. | скачати
Схожі роботи:
Типи даних в Object Pascal
Об`єктно-орієнтоване середовище програмування Object Pascal в профільному курсі інформатики
Розробка програми на мові Borland Object Pascal Ide Borland Delphi
Основні відомості про алгоритмічну мову Turbo Pascal Графіка Pascal
Pascal 9
Програмування Pascal
Turbo Pascal
Паскаль Pascal Блез
Оператори Turbo Pascal 7