C#. Абстрактний клас. Основні поняття. Приклади




Абстрактний клас. Основні поняття. Ключове слово abstract. Приклади


Зв’язані теми


Пошук на інших ресурсах:

1. Поняття абстрактного класу. Необхідність використання абстрактного класу. Приклад

Бувають випадки, коли потрібно створити найбільш загальну форму базового класу, яка буде наповнюватись деталями у похідних (успадкованих) класах. У такому випадку елементи базового класу (методи, властивості тощо) носять надто невизначений характер і реалізовувати їх не має сенсу. Класи, що містять елементи без конкретної релізації, називаються абстрактними. В абстрактному класі оголошується тільки загальний характер елементу, який буде наповнюватись змістом в успадкованих класах.

Абстрактний клас – це клас, в якому оголошується хоча б один абстрактний елемент (метод, властивість). Якщо в абстрактному класі оголошено абстрактний елемент, (метод, властивість) то перед іменем такого класу ставиться ключове слово abstract. Якщо у похідному класі потрібно визначити конкретну реалізацію елементу (методу, властивості) абстрактного класу, то при оголошенні елементу вказується ключове слово override.

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

Наприклад. Нехай потрібно розробити базовий клас Figure, який описує деяку фігуру. З цього класу повинні бути успадковані більш конкренті реалізації фігур: трикутник (Triangle), коло (Circle), прямокутник (Rectangle) як зображено на рисунку 1.

Нехай в ієрархію класів потрібно ввести метод Area(), який визначає площу фігури. У базовому класі Figure та похідних класах, метод Area() використовує механізм поліморфізму при його виклику.

Реалізація методу Area() в похідних класах (Triangle, Circle, Rectangle) є зрозумілою. Для кожного з цих похідних класів існує свій спосіб визначення площі. Однак, неможливо визначити площу для методу Area() базового класу Figure, оскільки, на цьому етапі ще не відомо для якої фігури потрібно обчислювати площу. Тому, реалізація (тіло) методу Area() не має сенсу. Такий метод доцільно оголошувати як абстрактний з ключовим словом abstract. Автоматично, клас Figure також стає абстрактним.

C#. Абстрактні класи. Необхідність використання абстрактних класів. Абстрактний метод

Рисунок 1. Необхідність використання абстрактних класів.
Метод Area() у класі Figure є абстрактним

 

2. Загальна форма оголошення абстрактного класу. Ключове слово abstract

Щоб оголосити абстрактний клас потрібно використати ключове слово abstract. У найпростішому випадку загальна форма оголошення абстрактного класу з іменем ClassName наступна

abstract class ClassName
{
  // Абстрактні та неабстрактні елементи
  // ...
}

Згідно синтаксису C# перед ключовим словом abstract може використовуватись модифікатор доступу до класу public або internal.



 

3. Які елементи класу можуть бути абстрактними? Приклад

З ключовим словом abstract можна оголошувати:

  • методи;
  • властивості;
  • індексатори;
  • події.

Неможна оголосити абстрактне поле (змінну) класу.

Приклад. У прикладі демонструється оголошення різних абстрактних елементів класу.

...

// Оголосити тип делегату
delegate int MyDelegate(int a, int b);

abstract class A
{
  // Абстрактний метод
  public abstract void Print();

  // Абстрактна властивість
  public abstract int IntProp
  {
    get;
    set;
  }

  // Абстрактний індексатор
  public abstract int this[int index]
  {
    get;
    set;
  }

  // Абстрактна подія
  public abstract event MyDelegate MyEvent;
}

...

 

4. Що таке абстрактний метод? Загальна форма оголошення абстрактного методу

Абстрактний метод – це метод, в якому відсутня реалізація. Іншими словами, абстрактний метод не містить тіла методу. Для абстрактного методу задається тільки його сигнатура: тип повернення, ім’я та список параметрів.

Загальна форма оголошення абстрактного методу:

access_modifier abstract return_type MethodName(parameters);

тут

  • MethodName – ім’я методу.
  • access_modifier – один з модифікаторів доступу protected, public, internal, protected internal;
  • return_type – тип, який повертає метод;
  • parameters – список параметрів методу.

 

5. Загальна форма оголошення абстрактної властивості

Загальна форма оголошення абстрактної властивості

access_modifier abstract return_type PropName
{
  get; set;
}

тут

  • PropName – ім’я властивості;
  • access_modifier – один з модифікаторів доступу крім модифікатора private;
  • return_type – тип властивості.

Як і у випадку звичайної властивості, специфікатори доступу get або set можуть бути відсутні.

 

6. Загальна форма оголошення абстрактного індексатора

У C# допускається використання абстрактних індексаторів. Загальна форма оголошення абстрактного індексатору наступна:

access_modifier abstract return_type this[type_index index]
{
  get;
  set;
}

тут

  • access_modifier – один з модифікаторів доступу крім модифікатора private;
  • return_type – тип індексатора;
  • type_index – тип індексу, за яким отримується значення по індексатору;
  • index – ім’я змінної-індексу.

Абстрактний індексатор повинен містити щонайменше один з специфікаторів get або set.

 

7. Загальна форма оголошення абстрактної події

Щоб оголосити абстрактну подію попередньо повинен бути оголошений тип делегату для цієї події. Загальна форма оголошення абстрактної події наступна:

access_modifier abstract event Delegate_Type eventName;

де

  • access_modifier – один з модифікаторів доступу: public, protected, internal або protected_internal;
  • eventName – ім’я абстрактної події;
  • Delegate_Type – тип делегату.

Тип делегату Delegate_Type оголошується як

delegate return_type Delegate_Type(parameters);

тут

  • Delegate_Type – ім’я типу делегату;
  • return_type – тип, який повертає делегат;
  • parameters – параметри, які отримує делегат.

 

8. Які обмеження накладаються на абстрактні класи та їх екземпляри?

На абстрактні класи накладаються наступні обмеження:

  • абстрактний клас не може бути статичним (static);
  • абстрактний клас не може бути запечатаним (sealed);
  • неможливо створити екземпляр (об’єкт) абстрактного класу.

 

9. Чи можна в абстрактному класі оголошувати не абстрактні елементи?

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

 

10. Чи можна використовувати конструктори в абстрактному класі?

В абстрактному класі допускається використання конструкторів. Хоча екземпляр абстрактного класу створити неможна. Конструктори в абстрактному класі необхідні для реалізації початкової ініціалізації внутрішніх полів абстрактного класу (якщо такі є). Ці конструктори викликаються з допомогою ключового слова base у похідних класах. Більш детально про особливості використання ключового слова base у конструкторах похідних класів описується тут.

 

11. Які обмеження накладаються на абстрактні елементи класу (методи, властивості)?

Абстрактні елементи класу – це елементи, які оголошені з ключовим словом abstract. На абстрактні елементи (методи, властивості, індексатори, події) накладаються наступні обмеження:

  • абстрактний елемент не може бути private. Допускається оголошувати абстрактний метод з будь-яким іншим модифікатором доступу: public, protected, internal, protected internal;
  • абстрактний елемент не повинен мати реалізації;
  • абстрактний елемент (елемент, позначений як abstract) не може бути позначений ключовим словом virtual. Це зрозуміло, оскільки для забезпечення використання поліморфізму достатньо ключового слова abstract.

 

12. Чи може абстрактний клас не містити оголошення абстрактних елементів?

Так, може. Компілятор C# допускає оголошення класу з ключовим словом abstract в якому немає абстрактних елементів.
Така властивість є корисною, коли на початковому етапі побудови програми ще до кінця не відомо перелік усіх елементів класу, який знаходиться в вершині ієрархії. Однак вже зрозуміло, що при подальшій розробці (розвитку) програми, цей клас буде містити абстрактні елементи, а, отже, має бути абстрактним.

Наприклад. На початку розробки ієрархії класів вводиться абстрактний клас-заглушка. У даному прикладі оголошується клас з іменем BaseAbstractClass

// Базовий клас в ієрархії, ще поки що
// не містить абстрактних елементів
abstract class BaseAbstractClass
{
  // Тут в майбутньому можуть бути
  // додані абстрактні елементи
}

 

13. Рисунок, що демонструє використання абстрактного класу

 

C#. Спадковість. Використання абстрактного класу

Рисунок 2. Використання абстрактного класу

 

14. Чи може абстрактний клас успадковувати інший абстрактний клас? Чи може абстрактний клас успадковувати інший не абстрактний клас?

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

Приклад. Нижченаведений приклад демонструє свободу у використанні абстрактних класів у поєднанні з неабстрактними.

namespace ConsoleApp5
{
  // Абстрактний клас A_Abstract - вершина ієрархії
  abstract class A_Abstract
  {
    // деяке внутрішнє поле класу
    public int a;
  }

  // Не абстрактний клас B - похідний від A_Abstract
  class B : A_Abstract
  {
    public int b;
  }

  // Абстрактний клас C_Abstract - похідний від неабстрактного класу B
  abstract class C_Abstract : B
  {
    public int c;
  }

  // Не абстрактний клас D
  class D : C_Abstract
  {
    public int d;
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Оголосити екземпляри класів B, D.
      // Екземпляри класів A_Abstract, C_Abstract заборонено оголошувати
      B objB = new B();
      D objD = new D();
      // A_Abstract objA = new A_Abstract(); - помилка

      // 2. Доступ до елементів з екземпляру objB
      objB.a = 23;
      objB.b = 33;
      // objB.d = 40; - помилка, неможливо доступитись до елементу успадкованого класу

      // 3. Доступ до елементів з екземпляру objD
      objD.a = 77;
      objD.b = 777;
      objD.c = 7777;
      objD.d = 7777;
    }
  }
}

 

15. Відмінності між абстрактними класами та інтерфейсами

Між інтерфейсами та абстрактними класами було помічено наступні відмінності:

  • в інтерфейсі не можна оголошувати реалізації методів, властивостей тощо. В абстрактному класі допускається оголошувати реалізації його елементів;
  • інтерфейс не може мати конструктори. Абстрактний клас може мати конструктори;
  • інтерфейс не може містити поля даних. Абстрактний клас допускає використання внутрішніх полів даних;
  • елементи інтерфейсу за замовчуванням (без модифікатора доступу) вважаються public. В абстрактних класах елементи за замовчуванням вважаються private;
  • елементи інтерфейсу не повинні містити модифікатора доступу (інакше компілятор видасть повідомлення про помилку). В абстрактних класах допускається наявність будь-якого модифікатора доступу в оголошенні елементу класу;
  • похідний клас може успадковувати тільки один абстрактний базовий клас. У випадку використання інтерфейсів похідний клас може успадковувати будь-яку кількість інтерфейсів. Таким чином, інтерфейс – це альтернатива абстрактного класу, з допомогою якої можна здійснити множинну спадковість.

 


Зв’язані теми