Цей курс присвячений середовищі розробки Delphi фірми Borland (відомої такожяк Inprise), яка протягом багатьох років успішно витримує (івиграє!) жорстку конкуренцію з іншими середовищами програмування.
Концепція Delphi1 була реалізована в кінці 1994 року, коли вийшла першаверсія середовища розробки. В основу цього програмного продукту лягликонцепції об'єктно-орієнтованого програмування (ООП) на базі мови
Object Pascal і візуального підходу до побудови додатків.
Після виходу Delphi 1 всі комп'ютерні видання писали про цю середовищі, як про
"Вбивці Visual Basic". Поява Delphi 2 (32-розрядної) ознаменувало новуепоху, - з'явився доступ до можливостей програмних інтерфейсів Windows NTі Windows 95, протоколів OLE. Delphi 2 стала засобом розробкиповноцінних додатків клієнт/сервер. Незабаром Delphi 3 надаларозробникам засоби створення розподілених багаторівневих додатків іповноцінний інструментарій проектування додатків для Internet іintranet. З'явилася повноцінна підтримка COM - моделі об'єктів, що сталанаріжним каменем сучасного програмування. Четверта версія Delphiдозволяє повністю інтегрувати ваші розробки з об'єктами COM.
Підтримка архітектури CORBA (Common Object Request Broker Architecture)відкриває перед додатками, створеними в Delphi для платформи Wintel
(Windows + Intel), світ інших операційних систем (UNIX, OS/2, WMS).
Спілкуватися з великими корпоративними СУБД стало також просто, як і зі старимдобрим Paradox. Ви можете використовувати у своїй роботі будь-які рівнімежзадачного взаємодії: від найпростішого на рівні гнізд, до зв'язку зтакими перспективними інструментами, як Microsoft Transaction Server.
Delphi представляє наступні нові властивості і удосконалення: p>
. Нові розширення мови. У Delphi в мову Object Pascal включені динамічні масиви, методи обробки переповнення, установка значення параметрів за замовчуванням, і багато іншого. P>
. Менеджер Проекту Новий менеджер проекту дозволяє Вам об'єднувати проекти, які працюють разом в один проектну групу. Це дозволяє Вам організувати роботу взаємозалежних проектів, таких як однозадачние і багатозадачні програму або DLL, так і спільну роботу виконуваних програм. P>
. Новий провідник Новий провідник містить виконувані класи, навігацію по модулях, і браузер коду. Провідник коду робить створення класів простіше, автоматизують багато хто з кроків. Введіть прототип методу в розділі інтерфейсу і властивість виконується класу згенерує кістковий код в розділі реалізації. Також провідник дозволяє швидко переміщатися через файли модуля, а так само між інтерфейсом і реалізацією. Використання символу Tooltip, дозволяє переглядати інформацію про оголошення будь-якого ідентифікатора, потім використовуючи борузер код, можна перейти до його оголошення. P>
. Закріплюються вікна інструментів. IDE (Інтегрована середу азработкі) містить більше перенастраеваемую конфігурацію вікон інструментів, які можна закріплювати з редактором коду. Просто перетягніть і відпустіть вікно інструмента до того місця, до якого хочете. Провідник коду та менеджер проекту можна як закріплювати, так і незакреплять. P>
. Покращена налагодження. Інтегрований відладчик має багато нових властивостей, включаючи віддалену і багатопроцесорну налагодження, перегляд коду центрального процесора, інспекторів, вдосконалені точки переривання, відладчик специфічних підменю та закріплених вікон. P>
. Підтримка MTS. Явна підтримка для використання MTS інтегрована в підтримку багаторівневих баз даних. Крім того, новий майстер полегшить p>
Вам створення об'єктів сервера MTS. P>
. Удосконалення ActiveX. P>
. Delphi забезпечує розширену підтримку ActiveX. P>
. Удосконалення VCL. Ієрархія об'єктів Delphi бида розширена, щоб включити новий компонент для NT Service додатків. Крім того, новий компонент виконуваного списку (на Стандартної сторінці палітри), дозволяє Вам централізувати управління меню і команд від кнопок. P>
Управління VCL розширене, щоб підтримуються drag-and-drop перетягування, забезпечувати додатковий контроль над розміщенням вікна , і багато іншого. p>
. Підтримка RTL для 2000-го року. P>
. Глобальна мінлива TwoDigitYearCenturWwindow використовується функціями p>
StrtToDate і StrToTateTime, щоб управляти інтерпретацією років з двома цифрами при перетворенні дат. P>
. Підтримка CORBA. Версії Клінт/Сервер і підприємство включають підтримку для CORBA клієнт і сервер додатків. Майстри допоможуть Вам легко створити сервер CORBA і Динамічний Інтерфейс Виклику (DII), дозволяючи p>
Вам записувати клієнтів для існуючих серверів CORBA. CORBA має можливість підтримки в багато-рівневий баз даних. Ви можете навіть створити сервер, який обробляє COM клієнтів та CORBA клієнтів одночасно.
Delphi - це комбінація кількох найважливіших технологій: p>
. Високопродуктивний компілятор в машинний код p>
. Об'єктно-орієнтована модель компонент p>
. Візуальне (а, отже, і швидкісний) побудова додатків з програмних прототипів p>
. Масштабуються засоби для побудови баз даних
Компілятор, вбудований в Delphi, забезпечує високу продуктивність,необхідну для побудови додатків в архітектурі "клієнт-сервер". Вінпропонує легкість розробки і швидкий час перевірки готовогопрограмного блоку, характерного для мов четвертого покоління (4GL) і втой же час забезпечує якість коду, характерного для компілятора 3GL.
Крім того, Delphi забезпечує швидку розробку без необхідності писативставки на Сі або ручного написання коду (хоча це можливо).
У процесі побудови програми розробник вибирає з палітри компонентготові компоненти як художник, що робить великі мазки пензлем. Ще докомпіляції він бачить результати своєї роботи - після підключення до джереладаних їх можна бачити відображеними на формі, можна переміщатися поданими, представляти їх у тому чи іншому вигляді. У цьому сенсі проектування в
Delphi мало чим відрізняється від проектування в інтерпретує середовищі,однак після виконання компіляції ми отримуємо код, який виконується в
10-20 разів швидше, ніж те ж саме, зроблене за допомогою інтерпретатора.
Крім того, компілятор компілятору різниця, в Delphi компіляція проводитьсябезпосередньо в рідний машинний код, в той час як існуютькомпілятори, що перетворюють програму у так званий p-код, який потімінтерпретується віртуальною p-машиною. Це не може не позначитися нафактичне швидкодії готового додатку.
Об'єктно-орієнтована модель програмних компонент. Основний акцент цієїмоделі в Delphi робиться на максимальному реіспользованіі коду. Цедозволяє розробникам будувати програми досить швидко з заздалегідьпідготовлених об'єктів, а також дає їм можливість створювати своївласні об'єкти для середовища Delphi. Ніяких обмежень за типамиоб'єктів, які можуть створювати розробники, не існує.
Дійсно, все в Delphi написано на ньому ж, тому розробники маютьдоступ до тих же об'єктів та інструментів, які використовувалися длястворення середовища розробки. У результаті немає жодної різниці міжоб'єктами, що поставляються Borland або третіми фірмами, і об'єктами, яківи можете створити.
У стандартну поставку Delphi входять основні об'єкти, які утворюютьвдало підібрану ієрархію базових класів. Але якщо виникненеобхідність у рішенні якоїсь специфічної проблеми на Delphi,радимо, перш ніж спробувати починати вирішувати проблему "з нуля",переглянути список вільно розповсюджуваних або комерційних компонент,розроблених третіми фірмами, кількість цих компонентів в даний часскладає декілька тисяч. Подієва модель в Windows завжди була складнадля розуміння і налагодження. Але саме розробка інтерфейсу в Delphi єнайпростішим завданням для програміста.
Об'єкти БД в Delphi засновані на SQL і включають в себе повну потужність Borland
Database Engine. До складу Delphi також включено Borland SQL Link, томудоступ до СУБД Oracle, Sybase, Informix і InterBase відбувається з високоюефективністю. Крім того, Delphi включає в себе локальний сервер
Interbase для того, щоб можна було розробити розгортаються на будь-якізовнішні SQL-сервера додатки в офлайновом режимі. азработчік в середовищі
Delphi, який проектує інформаційну систему для локальної машини (доНаприклад, невелику систему обліку медичних карток для одногокомп'ютера), може використовувати для зберігання інформації файли формату. dbf
(як в dBase або Clipper) або. db (Paradox). Якщо ж він буде використовуватилокальний InterBase for Windows (це локальний SQL-сервер, що входить допостачання), то його програму без жодних змін буде працювати і вскладі великої системи з архітектурою клієнт-сервер. Ось вона --масштабованість на практиці - одна і та ж програма може використовуватияк для локального, так і для більш серйозного клієнт-серверного варіантів. p>
1. Основи об'єктно-орієнтованого програмування
Поняття класу.
Класом в Delphi називається особливий тип, який може мати у своєму складіполя, методи і властивості. Такий тип також називають об'єктним типом. P>
type p>
tMyClass = class (tObject) p>
fMyFiled: integer; p>
function MyMethod: integer; p>
end;
Поля класу аналогічні полям запису. Це - дані, унікальні в програмідля кожного створеного в програмі екземпляра класу. Описаний вище класtMyClass має одне поле - fMyFiled. На відміну від полів, методи у двохекземплярів одного класу загальні. Методи - це процедури і функції,описані усередині класу, і призначені для операцій над його полями. Ускладу класу входить покажчик на спеціальну таблицю - таблицю віртуальнихметодів (VMT), в якій міститься вся інформація, необхідна для дзвінкаметодів. Від звичайних процедур і функцій методи відрізняються тим, що привиклик до них передається покажчик на екземпляр класу, що їх викликав.
Тому оброблятися будуть поля саме того об'єкта, що викликавметод. Всередині методів покажчик на що викликав їх об'єкт доступний череззарезервоване слово Self. Властивістю класу називається сукупність поляі методів читання/запису, що забезпечують доступ до цього поля. При цьому самеполе декларується як private (доступно лише всередині даного класу), ідоступ до нього можливий тільки за допомогою відповідних методів.
Подробнее властивості будуть обговорюватися нижче.
Поняття об'єкта
Щоб використовувати новий тип в програмі, потрібно, як мінімум, визначитизмінну цього типу. Змінна об'єктного типу називається екземпляромтипу або об'єктом: p>
var aMyObject: tMyClass;
До введення поняття "клас" у мові Pascal існувала двозначністьвизначення "об'єкт", який міг позначати і тип, і змінну цьоготипу. Тепер існує чітка границя: клас - це опис, об'єкт - те,що створена відповідно з цим описом.
Створення і знищення об'єктів
На відміну від С + + і Turbo Pascal в Delphi об'єкти можуть бути тількидинамічними!. Це означає, що в наведеному вище прикладі мінливаaMyObject насправді є покажчиком, що містить адресу об'єкта.
Об'єкт створюється конструктором і знищується деструкторами. P>
aMyObject: = tMyClass.Create; p>
// p>
// дії зі створеним об'єктом p>
// p>
aMyObject.Destroy; < br>Слід звернути увагу на те, що для створення об'єкта aMyObjectвикликається метод класу tMyClass.Create. Конструктор класу (і ряд іншихметодів) успішно працює і до створення об'єкта. Однак більшість звичайнихметодів (зокрема всі віртуальні та динамічні методи). Викликати доініціалізації об'єкта не слід.
У Delphi конструкторів у класу може бути кілька. Загальноприйнято називатиконструктор Create, на відміну від Turbo Pascal, де конструктори називалися
Init, і С + +, в якому ім'я конструктора збігається з ім'ям класу. Типовеназва деструктора - Destroy. p>
type p>
tMyClass = class (tObject) p>
fMyFiled: integer; p>
Constructor Create; p>
Destructor Destroy; p> < p> function MyMethod: integer; p>
end;
Для знищення об'єкта в Delphi рекомендується використовувати не деструкція,а метод Free, що спочатку перевіряє покажчик, і тільки потімвикликає деструктор Destroy: p>
procedure tObject.Free;
До передачі керування тілу конструктора відбувається власне створенняоб'єкту: під нього приділяється пам'ять, значення всіх полів обнуляються. Далівиконується код конструктора, написаний програмістом для ініціалізаціїоб'єктів даного класу. Таким чином, незважаючи на те, що синтаксисконструктора схожий з викликом процедури (відсутній повертається значення),насправді конструктор - це функція, що повертає створений іпроініціалізувати об'єкт.
Примітка. Конструктор створює новий об'єкт лише в тому випадку, якщоперед його ім'ям вказано ім'я класу. Якщо вказати ім'я вже існуючогооб'єкта, він поведе себе по-іншому: не створить новий об'єкт, а тількивиконає код, що міститься в тілі конструктора.
Щоб правильно проініціалізувати в створюваному об'єкті поля, що відносятьсядо класу - предка, потрібно відразу ж при вході в конструктор викликатиконструктор предка за допомогою зарезервованого слова inherited: p>
constructor tMyClass.Create; p>
Begin p>
inherited Create; p>
// Код ініціалізації tMyClass p>
End;
Як правило, в коді програм, написаних на Delphi, практично нзустрічається викликів конструкторів і деструкторів. Справа в тому, що будь-якийкомпонент, який потрапив при візуальному проектуванні в додаток з палітрикомпонентів, включається у певну ієрархію. Ця ієрархія замикається наформі (клас tForm): для всіх її складових частин конструктори ідеструктори викликаються автоматично, незримо для програміста. Хто створюєі знищує форми? Це робить додаток (об'єкт з ім'ям Application). Уфайлі проекту (з розширенням DPR) ви можете побачити виклики методу
Application.CreateForm, призначеного для цієї мети.
Що стосується об'єктів, що створюються динамічно (під час виконанняпрограми), то тут потрібен явний виклик конструктора і методу Free.
Властивості
Як відомо, існує три основних принципи, що становлять суть об'єктно -орієнтованого програмування: інкапсуляція, наслідування іполіморфізм. Класичне правило об'єктно-орієнтованогопрограмування стверджує, що для забезпечення надійності небажанийпрямий доступ до полів об'єкта: читання і зміна їх вмісту повиннездійснюватися за допомогою виклику відповідних методів. Це правилоназивається інкапсуляцією (приховання даних). У старих реалізаціях ООП
(наприклад в Turbo Pascal) ця думка впроваджувалася тільки за допомогою закликіві прикладів в документації; в Delphi є відповідна конструкція.
Користувач об'єкту в Delphi може бути повністю відгороджений від полівоб'єкта за допомогою властивостей.
Зазвичай властивість визначається трьома елементами: полем і двома методамищо здійснюють його читання/запис: p>
type p>
tMyClass = class (tObject) p>
function GetaProperty: tSomeType; p>
procedure SetaProperty (Value: tSomeType); p>
property aProperty : tSomeType read GetaProperty p>
write SetaProperty; p>
end;
У даному прикладі доступ до значення властивості aProperty здійснюється черезвиклики методів GetaProperty і SetaProperty, однак у зверненні до цихметодів у явному вигляді немає необхідності: досить написати p>
aMyObject.aProperty: = aValue; p>
aVarable: = aMyObject.aProperty;і Delphi відкомпілює ці оператори у виклики відповідних методів. Теє зовні властивість виглядає в точності як звичайне поле, але за всякимзверненням до нього можуть стояти виклики необхідних програмісту методів.
Наприклад, якщо є об'єкт, що представляє собою квадрат на екрані, і йоговластивості "колір" присвоюється значення "білий", то відбудеться негайнапромальовування, що приводить реальний колір на екрані у відповідність значеннювластивості.
У методах, що встановлюють значення властивості, може проводитися перевірказначення на попадання в заданий діапазон значень і виклик інших процедурщо залежать від внесених змін. Якщо ж потреби в спеціальнихпроцедурах читання/запису немає, можна замість імен методів застосовувати іменаполів. p>
tPropClass class = p>
fValue: tSomeType; p>
procedure SetValue (aValue: tSomeType); p>
property Value: tSomeType read fValue write SetValue; p> < p> End;
У цьому прикладі поле fValue модифікується за допомогою методу SetValue, ачитається безпосередньо.
Якщо властивість повинна тільки читатися чи тільки записуватися, у йогоописі може бути присутнім тільки відповідний метод: p>
tReadOnlyClass class = p>
property NotChanged: tSomeType read GetNotChanged; p>
End;
У цьому прикладі властивість є тільки для читання. Спроба присвоїтизначення властивості NotChanged викличе помилку компіляції.
Властивості можна присвоювати значення за замовчуванням. Для цього служитьключове слово default: p>
Property Visible: boolean read fVisible write SetVisible default TRUE;
Це означає, що при запуску програми властивість буде встановленокомпілятором в TRUE.
Властивість може бути і векторних. У цьому випадку воно виглядає як масив: p>
Property Points [index: integer]: tPoint read GetPoint write SetPoint;
Для векторної властивості необхідно описати не тільки тип елементів масиву,але також і тип індексу. Після ключових слів read і write повинні йти іменавідповідних методів. Використання тут полів масивів неприпустимо.
Метод, який читає значення векторної властивості, повинен бути описаний якфункція, що повертає значення того ж типу, що й елементи властивості, іяка має єдиний параметр того ж типу і з тим же ім'ям, що й індексвластивості: p>
function GetPoint (index: integer): tPoint;
Аналогічно, метод, що поміщають значення в таку властивість, повинен першимпараметром мати індекс, а друге - змінну потрібного типу. p>
procedure SetPoint (index: integer; Value: tPoint);
У векторних властивостей є ще одна важлива особливість: деякі класи в
Delphi (списки tList, набори рядків tStrings і т.д.) "побудовані" навколоодного основного векторного властивості. Основний метод такого класу даєдоступ до елементів деякого масиву, а всі основні методи є якб допоміжними. Для спрощення роботи з об'єктами подібного класуможна описати подібне властивість з ключовим словом default: p>
type tMyList class = p>
property list [Index: integer]: string read Getlist write Setlist; default; p>
end;
Якщо в об'єкта є така властивість, його можна не згадувати, а ставитиіндекс у квадратних дужках відразу після імені об'єкта: p>
var MyList: tMyList p>
Begin p>
MyList.list [1]: = 'First'; (Перший спосіб) p>
MyList. [2]: = ' Second '; (Перший спосіб) p>
End;
Вживаючи ключове слово default необхідно дотримуватися обережності, тому щодля звичайних і векторних властивостей воно вживається в різних значеннях.
Про роль властивостей у Delphi красномовно говорить той факт, що у всіх наявнихв розпорядженні програміста стандартних класів 100% полів недоступні ізамінені тими, що базуються на них властивостями. Того ж правила сліддотримуватися і при розробці власних класів.
Спадкування
Другим "стовпом" ООП є наслідування. Цей простий принцип означає,що якщо необхідно створити новий клас, лише трохи відрізняється від ужещо є, немає необхідності в переписування наново вже існуючогокоду. Ви заявляєте, що новий клас p>
tNewClass = class (tOldClass);є нащадком або дочірнім класом класу tOldClass, званогопредком або батьківським класом, і додаєте до нього нові поля методи івластивості.
У Delphi всі класи є нащадками класу tObject. Тому, якщо вибудуєте дочірній клас прямо від tObject, то у визначенні його можна незгадувати. Наступні два опису однаково вірні: p>
tMyClass = class (tObject); p>
tMyClass = class;
Більш докладно клас tObject буде розглянуто нижче.
Успадковані від класу-предка поля і методи доступні в дочірньому класі;якщо має місце збіг імен методів, кажуть, що вони перекриваються.
Розглянемо поведінку методів при спадкуванні. По тому, які діївідбуваються при виклику, методи діляться на три групи. У першу групувіднесемо статичні методи, у другу - віртуальні (virtual) ідинамічні (dynamic) і, нарешті, в третьому - з'явилися тільки в Delphi 4перевантажуються (overload) методи.
Статичні методи, а також будь-які поля в класах-нащадках поводятьсяоднаково: можна без обмежень перекривати старі імена і при цьому мінятитип методів. Код нового статичного методу повністю перекриває (замінюєсобою) код старого методу: p>
type p>
tFirstClass class = p>
fData: Extended; p>
procedure SetData (aValue: Extended); p>
end; p>
tSecondClass = class (tFirstClass) p>
fData: Integer; p>
procedure SetData (aValue: Integer); p>
end; p>
procedure tFirstClass.SetData (aValue: Extended); p>
Begin p>
fData: = 1.0; p>
End; p>
procedure tFirstClass.SetData (aValue: Extended); p>
Begin p>
fData: = 1; p>
inherited SetData (0.99); p>
End;
У цьому прикладі різні методи з ім'ям SetData присвоюють значення різнимполями з ім'ям fData. Перекриття (однойменне) поле предка недоступно внащадку. Тому два однойменних поля з ім'ям fData приведені тільки дляприкладу.
На відміну від поля, усередині інших методів перекритий метод доступний привказівці ключового слова inherited. За замовчуванням методи об'єктів класівстатичні - їх адресу визначається ще на етапі компіляції проекту,тому вони викликаються найшвидше.
Принципово відрізняються від статичних віртуальні та динамічні методи.
Вони повинні бути оголошені шляхом додавання відповідної директивиdynamic або virtual. З точки зору успадкування методи цих двох категорійоднакові: вони можуть бути перекриті в дочірньому класі тільки однойменнимиметодомі, що мають той же тип.
Поліморфізм. Віртуальні і динамічні методи
Наведемо приклад. Нехай є якесь узагальнене поле длязберігання даних - клас tFiled і три його нащадка - для зберігання рядків,цілих та дійсних чисел: p>
type p>
tFiled class = p>
function GetData: string; virtual; abctract; p>
end; p>
tStringFiled = class (tFiled) p>
fData: string; p>
function GetData: string; override; p>
end; p>
tIntegerFiled = class (tFiled) p>
fData: Integer; p>
function GetData: string; override; p>
end; p>
tExtendedFiled = class (tFiled) p>
fData: Extended; p>
function GetData: string; override; p>
end; p>
function tStringFiled.GetData: string; p>
Begin p>
Result: = fData; p>
End; p>
function tIntegerFiled.GetData: string; p>
Begin p>
Result: = IntToStr (fData); p>
End; p>
function tExtendedFiled.GetData: string; p>
Begin p>
Result: = FloatToStr (fData, ffFixed, 7, 2); p>
End; p> < p>function ShowData (aFiled: tFiled): string; p>
Begin p>
Form1.Label1.Caption: = aFiled.GetData; p>
End;
У цьому прикладі класи містять різнотипні поля даних fData, а також маютьуспадкований від tFiled віртуальний метод GetData, який повертає дані ввигляді рядка. Зовнішня по відношенню до них процедура ShowData отримує об'єкту вигляді параметра і показує цей рядок.
Відповідно до правил контролю відповідності типів (typecasting) ObjectPascal,об'єкту, як вказівником на екземпляр класу, може бути присвоєно адресапримірника будь-якого з дочірніх типів. Це означає, що в попередньому прикладів процедуру ShowData можна передавати об'єкти класів tStringFiled,tIntegerFiled, tExtendedFiled і будь-якого іншого нащадка tFiled.
Але якою (точніше, чий) метод GetData буде при цьому викликаний? Той, якийвідповідає класу фактично переданого об'єкта. Цей принципназивається поліморфізмом.
У попередньому прикладу, відзначимо, що у компілятора немаєможливості визначити клас об'єкта, фактично переданого в процедуру
ShowData на етапі компіляції. Механізм, що дозволяє визначити цей класпрямо під час виконання називається пізнім зв'язуванням. Природно,такий механізм повинен бути пов'язаний з переданим об'єктом. Для цього служитьтаблиця віртуальних методів (Virtual Method Table, VMT) і таблицядинамічних методів (Dynamic Method Table, DMT).
Розходження між віртуальними і динамічними методами полягає вособливості пошуку адреси. Коли компілятор зустрічає звернення довіртуального методу, він підставляє замість прямого виклику по конкретномуадресою код, який звертається до VMT і витягує звідти потрібну адресу. Такатаблиця є для кожного класу. У ній зберігаються адреси всіх віртуальнихметодів класу, незалежно від того, успадковані чи вони від предка абоперекриті в даному класі. Звідси і достоїнства і недоліки віртуальнихметодів: вони викликаються порівняно швидко, однак для зберігання покажчиківна них в таблиці VMT потрібна велика кількість пам'яті.
Динамічні методи викликаються повільніше, але дозволяють більш ощадливовитрачати пам'ять. Кожному динамічному методу системою присвоюєтьсяунікальний індекс. У таблиці динамічних методів класу зберігаються індекситільки тих методів тільки тих динамічних методів, які описані вданому класі. Коли Ви робите динамічного методу відбувається пошук в ційтаблиці. У випадку невдачі проглядаються DMT всіх класів-предків упорядку їхньої ієрархії і, нарешті, tObject, де є стандартний обробниквиклику динамічних методів. Економія пам'яті очевидна.
Для перекриття і віртуальних та динамічних методів служить директиваoverride, за допомогою якої (і тільки з нею!) можна перевизначати обидва цихтипу методів. p>
type p>
tParentClass class = p>
fFirstFiled: Integer; p>
fSecondFiled: longInt; p>
procedure StaticMethod; p>
procedure VirtualMethod1; virtual; p>
procedure VirtualMethod2; virtual; p>
procedure DynamicMethod1; dynamic; p>
procedure DynamicMethod2; dynamic; p>
end; p>
tChildClass = class (tParentClass) p>
procedure StaticMethod; p>
procedure VirtualMethod1; override; p>
procedure DynamicMethod1; override; p>
end; < br>Перший метод класу tChildClass створюється заново, два іншихперекриваються. Створимо об'єкти цих класів: p>
var Obj1: tParentClass; p>
Obj2: tChildClass;
Внутрішня структура цих об'єктів наведена нижче.
Перше поле кожного примірника кожного об'єкта містить вказівник на йогоклас. Клас, як структура складається з двох частин. Починаючи з адреси, наякий посилається вказівник на клас, розташовується таблиця віртуальнихметодів. Вона містить адреси всіх віртуальних методів класу, включаючи іуспадковані від предків. Перед таблицею віртуальних методів розташованаспеціальна структура, яка містить додаткову інформацію. У ніймістяться дані, повністю характеризують клас: ім'я, розмірпримірників, покажчики на клас-предок і т.д. Одне з полів структуримістить адресу таблиці динамічних методів класу (DMT). Таблиця маєтакий вигляд: на початку - слово, що містить кількість елементівтаблиці. Потім - слова, які відповідають індексами методів. Нумераціяіндексів починається з -1 і йде В порядку спадання. Після індексів йдутьвласне адреси динамічних методів. Слід звернути увагу на те,що DMT об'єкта Obj1 складається з двох елементів, Obj2 - з одного,відповідного перекритому методу DynamicMethod1. У разі виклику
Obj2.DynamicMethod2 індекс не буде знайдено в DMT Obj2, і станетьсязвернення до DMT Obj1. Саме так економиться пам'ять при використаннідинамічних методів.
Як зазначалося вище, вказівник на клас вказує на перший віртуальнийметод. Службові дані розміщуються перед таблицею віртуальних методів, тоє з негативним зміщенням. Ці зміщення описані в модулі SYSTEM.PAS: p>
vmtSelfPtr = -76 p>
vmtIntfTable = -72 p>
vmtAutoTable = -68 p>
vmtInitTable = -64 p>
vmtTypeInfo = -60 p>
vmtFiledTable = -56 p>
vmtMethodTable = -52 p>
vmtDynamicTable = -48 p>
vmtClassName = -44 p>
vmtInstanceSize = -40 p>
vmtParent = -36 p>
vmtSafeCallException = -32 p>
vmtAfterConstruction = -28 p>
vmtBeforeDestruction = -24 p >
vmtDispatch = -20 p>
vmtDefaultHandler = -16 p>
vmtNewInstance = -12 p>
vmtFreeInstance = -8 p>
vmtDestroy = -4
Поля vmtDynamicTable, vmtDispatch і vmtDefaultHandler відповідають за викликдинамічних методів. Поля vmtNewInstance, vmtFreeInstance і vmtDestroyмістять адреси методів створення та знищення примірників класу. ПоляvmtIntfTable, vmtAutoTable, vmtSafeCallException введені для забезпеченнясумісності з моделлю об'єкта COM. Інші поля доступні через методиоб'єкта tObject. У Object Pascal ця інформація відіграє важливу роль і можевикористовуватися програмістом неявно. У мові визначені два оператори - isі as, неявно звертаються до неї. Оператор is призначений для перевіркисумісності з присвоєння примірника об'єкта із заданим класом.
Вираз вигляду: p>
AnObject is tObjectType
Приймає значення True тільки якщо об'єкт AnObject сумісний з присвоєнняз класом tObjectType, тобто є об'єктом цього класу або йогонащадком.
Оператор as введений в мову спеціально для приведення об'єктних типів. З йогодопомогою можна розглядати екземпляр об'єкта як належить до іншогосумісного типу: p>
with AObjectOfSomeType as tAnotherType do. . .
Від стандартного способу приведення типів використання оператора asвідрізняється наявністю перевірки на сумісність типів під час виконання:спроба приведення до несумісному типу призводить до виникненнявиняткову ситуацію eInvalidCast. Після виконання оператора as самоб'єкт залишається незмінним, але виконуються ті його методи, яківідповідають що привласнюється класу.
Вся інформація, що описує клас, створюється і розміщується в пам'яті наетапі компіляції. Доступ до інформації поза методів цього класу можнаотримати, описавши відповідний вказівник, що називається покажчиком наклас чи покажчиком на об'єктний тип (class reference). Він описується придопомоги зарезервованих слів class of. Наприклад, покажчик на класtObject описаний в модулі SYSTEM.PAS і називається tClass. Аналогічніпокажчики визначені і для інших найважливіших класів: tComponentClass,tControlClass і т.д.
З покажчиком на клас тісно пов'язане поняття методів класу. Такі методиможна викликати і без створення екземпляра об'єкту - із зазначенням імені класув якому вони описані. Перед описом методу класу потрібно поставитиключове слово class.
Зрозуміло, методи класу не можуть використовувати значення, що містяться вполях класу: адже екземпляра класу не існує! Методи класу служатьдля отримання внутрішньої інформації класу. Нижче перераховані методи класуtObject:
Метод і моделі p>
сlass function ClassName: ShortString p>
Повертає ім'я класу p>
сlass function ClassNameIs (const Name: ShortString): Boolean p>
Приймає значення True, якщо ім'я класу одно заданому p>
сlass function ClassParent: tClass p>
Повертає вказівник на батьківський клас p>
сlass function ClassInfo: pointer p>
Повертає вказівник на структуру з додатковими даними проопублікованих методи і властивості. p>
сlass function InstanceSize: Longint p>
Повертає розмір екземпляра класу p>
сlass function InheritsFrom (aClass: tClass): Boolean p>
Повертає True, якщо даний клас успадковує від заданого p>
сlass function MethodAddress (const Name: ShortString): Pointer p>
Повертає адреса методу за його імені (тільки для опублікованих методів) p>
сlass function MethodName (Addres: pointer): ShortString p>
Повертає ім'я методу на його адресу (тільки для опублікованих методів)
У Delphi 4 в клас tObject додані ще два віртуальних методу -
AfterConstruction і BeforeDestruction. Як випливає з назви, вонивикликаються відразу після створення екземпляра об'єкта і безпосередньо передзнищенням.
Перевантаження методів
У Delphi 4 з'явився новий різновид методів - перевантажувати.
Перевантаження потрібна для того, щоб зробити однакові або схожі діїнад різнотипними даними. Перевантажуються методи описуються з ключовимсловом overload. p>
Type p>
tFirstClass class = p>
E: extended; p>
procedure SetData (aValue: Extended); overload; p>
end; p>
tSecondClass = class (tFirstClass) p>
I: integer; p>
procedure SetData (aValue: Integer); overload; p>
end;
Оголосивши метод SetData перевантажується, в програмі можна використовувати обидві йогореалізації одночасно. Це можливо тому, що компілятор визначає типпереданого параметра (цілий або дійсний) і залежно від цьогопідставить виклик відповідного методу.
Для перевантаження віртуального методу використовується зарезервоване словоreintroduce: p>
procedure SetData (aValue: string); reintrouce; overload;
На перевантаження методів накладається обмеження: не можна перевантажувати методи,що знаходяться в області видимості published.
Абстрактні методи
Абстрактними називаються методи, які визначені в класі, але не містятьніяких дій, ніколи не викликаються і обов'язково повинні бутиперевизначені в класах-нащадках. Абстрактними можуть бути тількивіртуальні та динамічні методи. Для опису абстрактного методувикористовується директива abstract: p>
Procedure NeverCallMe; virtual; abstract;
Жодного коду абстрактний метод не містить. Його виклик приведе до створеннявиняткову ситуацію eAbstractError.
Події
Операційна система Windows ® заснована на повідомленнях. Повідомлення цівиникають в результаті дій користувача, апаратури комп'ютера абоінших програм. Таких повідомлень у Windows сотні, і за великим рахунком,написати програму для Windows - значить визначити реакцію на деякі зних.
Працювати з такою кількістю повідомлень, навіть маючи під рукою довідник,нелегко. Тому одним з головних переваг Delphi є те, щопрограміст повністю позбавлений від необхідності працювати з повідомленнями
Windows (хоча така можливість у нього є). Типових подій в Delphi --не більше двох десятків, і всі вони мають просту інтерпретацію, що не вимагаєглибоких знань середовища.
З точки зору мови, подія - це поле процедурного типу, призначенедля створити власну реакції на ті чи інші вхідні дії: p>
Property OnMyEvent: tMyEvent read FMyEvent write FMyEvent;
Тут OnMyEvent - поле об'єкта, що містить адресу деякого методу.
Присвоїти такому властивості значення - значить вказати програмі адреса методу,який буде викликатися в момент настання події. Такі методиназиваються обробника подій.
Всередині бібліотеки Delphi виклики обробників подійзнаходяться всередині методів, що обробляють повідомлення Windows. Виконавшинеобхідні дії, цей метод перевіряє, відомий чи адресу обробника,і, якщо це так, викликає його.
Події мають різну кількість і тип установки, залежно відпоходження і призначення. Загальним для всіх події є параметр Sender
- Він вказує на об'єкт, що викликав подія. Найпростіше подія --tNotifyEvent - не має інших параметрів. p>
tNotifyEvent = procedure (Sender: tObject) of object;
Тип методу, призначений для сповіщення про натискання клавіші,передбачає передачу в процедуру коду цієї клавіші, про пересування миші
- Її поточних координат і т.д.
Назва події в Delphi починається з префікса On: OnClick, OnCreate,
OnMouseDown і т.д. Імена методів - обробників подій складаються з іменіоб'єкта, що генерує подія, і кореня імені події: OkButtonClick.
Двічі клацнувши мишею в інспектора об'єктів на сторінці Events в полінавпроти будь-якої події, ви отримаєте кістковий код (заготовку) цьогоподії.
Оскільки події - це властивості об'єкта, їх значення можна змінювати в будь-якіймомент під час виконання програми. Ця можливість називаєтьсяделегуванням. Можна в будь-який момент взяти спосіб?? реакції на події уодного об'єкта і привласнити (делегувати) їх іншому.
Принцип делегування дозволяє уникнути трудомісткого процесу породженнянових класів для кожного специфічного випадку, замінюючи нго простийпідстановкою процедур.
Один і той самий обробник може обробляти події від різних об'єктів.
Типовий приклад - у сучасних програмах одне і те ж дію можнавикликати декількома способами - через головне меню, контекстне меню і т.д. Цього легко домогтися, призначивши один і той же оброблювач всім необхіднимоб'єктам в інспектора об'єктів. азумеется, події повинні бути одного ітого ж типу.
Більш складний випадок - коли всередині обробника необхідно визначити,який саме об'єкт викликав подія. Якщо об'єкти, які потенційноможуть це зробити, мають різний тип, то саме їх тип можна застосувати вяк критерій: p>
If Sender is tMenuItem then ...
Якщо ж всі об'єкти, що розділяє між собою один обробник події,відносяться до одного класу, можна використовувати властивість tObject.Tag.
Нижче наведено назви деяких, найбільш уживаних подій Delphi: p>
Подія - Тип обробника - Коли виникає
OnClick - TNotifyEvent - При натисканні лівої клавіші миші
OnActivate - TnotifyEvent - Після передачі об'єкту фокусу
OnCreate - TnotifyEvent - Після створення об'єкта
OnDestroy - TnotifyEvent - Перед знищенням об'єкта
OnDeactivate - TnotifyEvent - Перед відходом фокусу з об'єкта
OnKeyPress - TkeyPressEvent - При натисканні клавіші
OnMouseDown - TmouseEvent - При натисканні клавіші миші
OnMouseMove - TmouseMoveEvent - Під час руху миші над об'єктом
OnMouseUp - TmouseEvent - При відпуску клавіші мишіа також їх типи: p>
Тип p>
Опис p>
TnotifyEvent p>
type TnotifyEvent = procedure (Sender: TObject) of object; p>
TkeyPressEvent p>
type TkeyPressEvent = procedure (Sender: TObject; var Key: Char) of object; p>
TmouseEvent p>
TmouseEvent = procedure (Sender: TObject; Button: TmouseButton; Shift:
TShiftState; X, Y: Integer) of object; p>
TmouseMoveEvent p>
TmouseMoveEvent = procedure (Sender: TObject; Shift: TShiftState; X, Y:
Integer) of object;
Стандартні події описані в модулі Classes.
Динамічні масиви
У Delphi існують динамічні масиви, тобто масиви, довжину якихможна змінювати під час виконання програми. аньше проблема динамічнихмасивів стояла досить гостро. Стандартних засобів для роботи з ними небуло, і програмістам доводилося вручну створювати подібні структури (якправило, на основі динамічних змінних). Тепер компілятор Delphi самвиконує всю "брудну" роботу. Паралельно з динамічними, в Delphiзбереглися і звичайні, статичні масиви.
Довжина динамічних масивів визначається вже під час виконання програми.
Описавши змінну як p>
var A1: array of real,ми будемо мати покажчик, відповідний масиву дійсних чисел.
Пам'ять під нього виділяється процедурою SetLength: p>
procedure SetLength (var A; NewLength: Integer);
Тут A - покажчик на динамічний масив, NewLength - довжина масиву.
У динамічних масивах нумерація індексів починається тільки з нуля.
Та обставина, що динамічні масиви фактично єпокажчиками, призводить до певних нюансів в їх використанні. Перший зних стосується присвоєння масивів. Запис p>
Var A1, A2: array [0 .. 4] of real; p>
A1: = A2;
У слу