Назад Уперед Зміст

Відношення спадкування

Класи А и В перебувають відносно спадкування, якщо між об'єктами цих класів існує відношення «є».

Наприклад, класи Квадрат і Прямокутник.

Ясно, що ці класи зв'язані відношенням спадкування, тому що «квадрат є прямокутником». Причому, батьківським класом є Прямокутник, а дочірнім Квадрат.

Тобто, якщо один клас є підмножиною іншого, то повинне бути використане спадкування.

Що таке спадкування

Зустрічаються класи, які дуже схожі, тобто мають багато загальних полів і методів (наприклад, клас автомобіль і клас спортивний автомобіль).

Якщо кожний клас описувати окремо, то буде багато повторюваного коду.

Спадкування це механізм за допомогою якого, один клас може використовувати властивості і методи іншого класу і додавати до них власні риси.

Зміст спадкування полягає в тому, що не треба з нуля описувати новий клас, а можна вказати батька (базовий клас) і описати відмінні риси нового класу.

У результаті, новий клас (він називається дочірнім) буде мати всі властивості батьківського класу плюс буде мати свої власні відмінні риси.

Опис дочірнього класу

Клас у С# може мати довільну кількість потомків і тільки одного предка.

При описі дочірнього класу (класу потомка), у заголовку після імені класу через двокрапку вказується батьківський клас (клас предка).

У прикладі клас В дочірній, а клас А батьківський.
  class В : А  
    {  }

Методи в дочірньому класі

Об'єкти дочірнього класу, створені в методі Main класу Program можуть викликати як методи батьківського класу так і власні методи.

Якщо ми прагнемо додати до дочірнього класу нову поведінку:

Якщо ми прагнемо для потомка перевизначити який-небудь метод, то в дочірньому класі цей метод описується з таким же іменем, але зі специфікатором new.

Перевизначення і перевантаження методів

Важливо розрізняти перевантаження методів і перевизначення методів.

Перевизначальний метод повинен мати те ж саме ім'я і список формальних параметрів, що і переобумовлений метод базового класу.

А в перевантаженого методу те ж ім'я, але інший список формальних параметрів. Тому якщо включити в дочірній клас метод з тим же самим іменем, що і метод у батьківському класі, але з іншим списком формальних параметрів, метод батьківського класу не буде перевизначений методом дочірнього. Дочірній успадкує метод батьківського класу.

Спадкування полів і методів батьківського класу

З дочірнього класу можна звернутися до полів батьківського класу, але для цього в батьківському класі поля повинні мати модифікатор protected.

З дочірнього класу можна викликати метод батьківського класу, застосовуючи його до об'єкта this.

Батько не має можливості звернутися до полів і методам потомка.

Конструктори в дочірньому класі

Потомок успадковує всі поля і методи батька, крім конструкторів.

Конструктори не успадковуються від батька, тому дочірній клас повинен мати власні конструктори.

У зв'язку із цим виникає наступне резонне питання: який конструктор відповідає за побудову об'єкта похідного класу: конструктор базового класу, конструктор похідного класу або ж обоє? На це питання можна відповісти так: конструктор базового класу конструює базову частину об'єкта, а конструктор похідного класу — похідну частину цього об'єкта. І в цьому є своя логіка, оскільки базовому класу невідомі і недоступні будь-які елементи похідного класу, а виходить, їхнє конструювання повинне відбуватися роздільно.

Якщо конструктор визначений тільки в похідному класі, те все відбувається дуже просто: конструюється об'єкт похідного класу, а базова частина об'єкта автоматично збирається його конструктором, використовуваним за замовчуванням.

Отже, оскільки дочірній об'єкт може користуватися полями батьківського класу ці поля повинні якимось образом одержати значення.

Тому при створенні об'єкта дочірнього класу спочатку потрібно викликати конструктор батьківського класу, який ініціалізує поля батьківського класу і тільки потім конструктор дочірнього класу для ініціалізації його полів.

Коли конструктори визначаються як у базовому, так і в похідному класі, процес побудови об'єкта трохи ускладнюється, оскільки повинні виконуватися конструктори обох класів. У цьому випадку доводиться звертатися до ключового слова base, яке знаходить двояке застосування: по-перше, для виклику конструктора базового класу; і по-друге, для доступу до члена базового класу, що ховається за членом похідного класу.

За допомогою форми розширеного оголошення конструктора похідного класу і ключового слова base у похідному класі може бути викликаний конструктор, певний у його базовому класі.

Для виклику конструктора батька в заголовку дочірнього конструктора використовується ключове слово base, що йменує батьківський клас. В base у дужках вказуються параметри відповідного конструктора батьківського класу, причому конструктор з такою кількістю параметрів (з такою сигнатурою) повинен обов'язково бути присутнім у батьківському класі.

Будь-який конструктор у дочірньому класі, який не викликає ініціалізатор конструктора базового класу за допомогою :base(Список параметрів), одержує ініціалізатор за замовчуванням, що привласнюється компілятором.

Приклад

У дочірньому класі об'єкт створюється з більшою кількістю параметрів, ніж в батьківському
//Батьківський клас. Із двома полями
class Found
{
//поля
protected string name;
protected int credit;
//конструктор батьківського класу
public Found(string name, int credit)
 {
    this.name = name;
    this.credit = credit;
 }
}
//Дочірній клас. І ще з одним полем
public class Derived:Found
{
// нове поле в дочірньому класі
int debit;
//конструктор дочірнього класу з 3 параметрами
public Derived (string x, int y, int z) : base(x, y)
 {  
	this.debit=z;
  }
}

При створенні об'єкта потомка перші два параметра будуть передаватися конструкторові батьківського класу із двома параметрами для ініціалізації його полів. Третій параметр ініціалізує поле об'єкта потомка.

Приклад

У дочірньому класі об'єкт створюється з меншою кількістю параметрів, ніж в батьківському
//Батьківський клас. Із трьома параметрами 
class Found
{
protected string name;
protected int credit;
protected int debit;
public Found(string name, int credit, int debit)
{
    this.name = name;
    this.credit = credit; this.debit = debit;
}
}
//Дочірній клас. Із двома параметрами 
public class Derived:Found
{
int ost;
public Derived(string x, int ost): base(x, ost)
{
    this.ost = ost;
 }
}

При створенні об'єкта потомка обоє параметра будуть передаватися конструкторові батьківського класу із двома параметрами для ініціалізації його полів. Ці же параметри ініціалізує поле об'єкта потомка.

Оскільки ми викликаємо конструктор батьківського класу із двома параметрами, то він повинен обов'язково існувати.

Тобто обов'язково в батьківському класі повинен бути приблизно такий конструктор:
public Found(string name, int ost)
{
   this.name = name;
   this.credit = ost; this.debit = ost;
 }

Весь код

У базовий і похідний клас додамо метод print().

У похідному класі можна визначити член з таким же іменем, як і в члена його базового класу. У цьому випадку член базового класу ховається в похідному класі. І хоча формально в C# це не вважається помилкою, компілятор все-таки видасть повідомлення, що попереджає про те, що ім'я ховається. Якщо член базового класу потрібно сховати навмисно, то перед його іменем слід указати ключове слово new, щоб уникнути появи подібного попереджуючого повідомлення. Слідує, мати на увазі, що це зовсім окремий додаток ключового слова new, не схоже на його застосування при створенні екземпляра об'єкта:

Приклад 1

Розглянемо спадкування класів на прикладі.

Раніше ми створили клас Triangle, що описує трикутники.

Цей клас буде в нас батьківським.

Кожний трикутник у класі Triangle однозначно визначався трьома закритими полями – довжинами трьох сторін. Щоб ці поля були доступні з дочірнього класу, опишемо їх зі специфікатором protected.

У класі були методи виводу на екран значень полів, обчислення периметра, площі по формулі Герона, а також логічний метод, що визначає існування трикутника.

Крім нього, у нас буде дочірній клас, що описує кольорові трикутники.

Новий клас, що описує кольорові трикутники назвемо Colortriangle. Він буде містити:

Усі члени класу Triangle (поля і методи) успадковуються класом Colortriangle.

Опис дочірнього класу Colortriangle:

Метод Main класу Program:

У методі Main є цикл із двох витків:

Відпрацьовування:

Приклад 2

Створити клас Armiya- армія, що містить:

Створити клас Potomok дочірній класу Armiya, що містить:

Для того щоб з дочірнього класу, викликати метод Q батьківського класу використовуємо об'єкт this.

У методі Main класу Program:

Відпрацьовування:

Приклад 3

Створити клас Transport- транспорт, що містить:

Створити клас Car (автомобіль) дочірній до класу Transport, що містить:

У класі Program:

Для транспортного засобу:

У класі Program для автомобіля:

Назад Уперед Зміст