
- •12.1. Класи й об’єкти. Основні поняття
- •12.2.Опис класів і об’єктів
- •12.3. Складові класів
- •12.4. Поняття успадкування
- •12.4. Поліморфізм. Віртуальні та динамічні методи
- •12.5. Структура опису класу
- •13. Класи загального призначення
- •13.1. Клас exception –- обробки виключень
- •13.2. Клас tlist – списки
- •13.3. Класи tstrings, tstringlist – набори рядків й об’єктів
12.4. Поняття успадкування
В основі класів лежать три фундаментальних принципи інкапсуляція, успадкування і поліморфізм. За першим принципом клас інкапсулює тобто включає поля, методи і властивості. За другим принципом клас має здатність успадковувати поля, методи і властивості інших класів. Розглянемо особливості цього принципу на прикладі
Клас TDiskGauge описує вимірювач дискового простору
Type
TDiskGauge=class
FDriveLetter:char;
FPercentCritical:integer;
Constructor Create;
Function GetPercentFree:integer;
Procedure CheckStatus;
Procedure SetPercentCritical
(Percent:integer);
Property PercentCritical: Integer read FPercentCritical write SetPercentCritical;
Property PercentFree:integer
read GetPercentFree;
end;
цей клас не може використовуватися для вимірювання іншого ресурсу, наприклад оперативної пам’яті. Для цього потрібний інший клас.
Type
TMemoryGauge=class
FPercentCritical:integer;
Constructor Create;
Function GetPercentFree:integer;
Procedure CheckStatus;
Procedure SetPercentCritical
(Percent:integer);
Property PercentCritical: Integer read FPercentCritical write SetPercentCritical;
Property PercentFree:integer
read GetPercentFree;
end;
Поля, методи і властивості класу TMemoryGauge аналогічні тим, що визначені у класі TDiskGauge. Відмінність тільки у відсутності поля FDriveLetter, інша реалізація конструктора Create і методу GetPercentFree. Якщо потрібно буде клас, що описує деякий інший вимірювач ресурсу, то знову слід буде описувати спільні поля, методи і властивості. Для того щоб уникнути дублювання атрибутів при визначенні нових класів у об’єктно-зорієнтованому програмуванні введено механізм успадкування. Для реалізації цього механізму слід виділити спільні атрибути всіх вимірювачів в окремий клас TResourceGauge.
Type
TResourceGauge=class
FPercentCritical:integer;
Constructor Create;
Function GetPercentFree:integer;
Procedure CheckStatus;
Procedure SetPercentCritical
(Percent:integer);
Property PercentCritical: Integer read FPercentCritical write SetPercentCritical;
Property PercentFree:integer
read GetPercentFree;
end;
Реалізація методів у класі TResourceGauge.
Constructor TResourceGauge.Create;
begin
FPercentCritical:=10;
end;
Function TResourceGauge.GetPercentFree:
integer;
Var Drive:Byte;
begin
Result:0;
end;
Procedure ResourceGauge.
SetPercentCritical(V:integer);
begin
if (v>=0)and(v<=100) then begin
FPercentCritical:=v; Beep; end;
end;
Procedure TResourceGauge.CheckStatus;
begin
if GetPercentFree <= PercentCritical then
Beep;
end;
При реалізації класу TResourceGauge нічого невідомо, що собою представляє ресурс, тому функція GetPercentFree повертає значення нуль. Очевидно, що створювати об’єкти цього класу немає змісту, але цей клас можна використати для породження інших класів , які описують конкретні види вимірювачів ресурсів – диску, оперативної пам’яті.
Type
TDiskGauge=class(ResourceGauge)
FDriveLetter:char;
Constructor Create(ADriveLetter:char);
Function GetPercentFree:integer;
end;
TMemoryGauge=class(ResourceGauge)
Function GetPercentFree:integer;
end;
Класи TDiskGauge і TMemoryGauge визначені як спадкоємці класу TResourceGauge це вказано в дужках після слова class. Вони автоматично включають у себе всі поля, методи і властивості класу TResourceGauge. Клас, який успадковує атрибути іншого класу називається породженим або потомком, а клас атрибути якого успадковуються називається предком. У відношеннях успадкування будь-який клас має тільки одного безпосереднього предка і може мати скільки завгодно потомків. Усі зв’язані відношенням успадкування класи утворюють ієрархію.
У мові Object Pascal існує попередньо описаний клас TObject, який є неявним предком усіх класів. Клас TObject виступає предком будь-якої ієрархії класів. Він містить ряд методів, які за спадком передаються всім класам. Серед них конструктор Create, деструктор Destroy, процедура Free та інші. Таким чином, ієрархія класів вимірювачів ресурсів має вигляд Рис. 12.3.
TObject
TResourceGauge
TMemoryGauge
TDiskGauge
Рис.12.3. Ієрархія класів вимірювачів ресурсів
У механізмі успадкування можна виділити три основних моменти:
успадкування полів;
успадкування методів;
успадкування властивостей.
Будь-який породжений клас успадковує від батьківського класу всі поля даних. Доступ до полів предка здійснюється за іменем, так ніби вони визначені у породженому класі. У спадкоємцях можна визначати нові поля, але їх імена повинні відрізнятися від імен полів предка. Непотрібні поля у спадкоємці вилучити неможливо.
Успадкування властивостей і методів має свої особливості. Властивість батьківського класу можна перекрити у породженому класі, наприклад щоб добавити їй новий атрибут доступу (було тільки читання, добавити запис) або зв’язати з іншим полем або методом.
Метод батьківського класу також можна перекрити у породженому класі для того щоб змінити алгоритм його роботи. У класах TDiskGauge та TMemoryGauge методи CheckStatus і SetPercentCritical успадковані від класу TResourceGauge, так як логіка їх роботи не залежить від типу ресурсу. А метод GetPercentFree перекритий, так як спосіб обчислення проценту вільного простору специфічний як для диску так і для оперативної пам’яті. Ці методи мають такий вигляд:
Function TDiskGauge.GetPercentFree:integer;
Var Drive:Byte;
begin
Drive:=ord(DriveLetter)-ord(‘A’)+1;
Result:=DiskFree(Drive)*100 div
DiskSize(Drive);
end;
Function TMemoryGauge.GetPercentFree:integer;
Var MemoryStatus:TMemoryStatus;
begin
MemoryStatus.dwLength:=Sizeof(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result:=100- MemoryStatus.dwMemoryLong;
end;
У класі TDiskGauge перекритий також і конструктор Create, це викликано необхідністю додатково ініціалізувати поле DriveLetter. Важливим є принцип реалізації конструкторів. Спочатку викликається конструктор предка, а потім ініціалізуються додаткові поля даних. У спадкоємці можна викликати перекритий метод предка, вказавши перед іменем зарезервоване слово Inherited. Наприклад,
Constructor TDiskGauge.Create( ADriveLetter:char);
Begin
Inherited Create;
DriveLetter:= ADriveLetter;
end;
У деструкторах виконується обернена послідовність дій, спочатку знищуються недоступні предку дані, а потім викликається успадкований деструктор.
Для класів зв’язаних відношенням успадкування існує правило сумісності типів. Об’єкту деякого класу предка можна присвоїти значення об’єкта будь-якого похідного класу, навпаки – невірно. Це правило застосовується при передачі об’єктів як параметрів у процедурах і функціях. Наприклад, якщо процедура працює з об’єктом класу TResourceGauge (предок), то замість нього можна передати об’єкт класу TDiskGauge або TMemoryGauge (потомки).
Оскільки реальний екземпляр об’єкт може виявитися спадкоємцем класу, вказаного при опису об’єктної змінної або параметра, то виникає необхідність перевірити до якого класу належить об’єкт. Кожний об’єкт зберігає інформацію про свій клас. У Object Pascal існують оператори is та as з допомогою яких виконується перевірка на тип і перетворення типу. Наприклад,
Var Obj: TObject;
щоб перевірити чи належить цей об’єкт до класу TResourceGauge або його спадкоємцю слід записати
if Obj is TResourceGauge then //Так належить
для перетворення об’єкту до потрібного типу використовується оператор as
with Obj as TResourceGauge do DiskGauge.