Підрозділ 4.6
Абстрактні класи та члени класів
Розглядає абстрактні класи, абстрактні методи й властивості, обов'язкову реалізацію в похідних класах і приклад фігур.
4.6. Абстрактні класи та члени класів
Навіщо потрібні абстрактні класи
Класи зазвичай представляють конкретні сутності, з яких можна створювати об'єкти: Patient, Doctor, Appointment. Але іноді корисно мати клас, який описує загальний шаблон або контракт для цілої групи класів, і при цьому самостійно не має сенсу як окремий об'єкт.
Наприклад, «медичний персонал» — це абстракція. У клініці є конкретні лікарі, медсестри, хірурги, але «медичного персоналу взагалі» як конкретної людини не існує. Проте всі вони мають спільне: ім'я, роль, спосіб виконання своїх обов'язків. Для опису таких сутностей у C# призначені абстрактні класи.
Абстрактний клас оголошується з ключовим словом abstract. Його головна особливість: неможливо створити екземпляр абстрактного класу безпосередньо. Він існує лише як база для похідних класів.
Абстрактний клас з конкретними методами
Абстрактний клас може мати звичайні поля, властивості, конструктори та методи — і похідні класи успадкують їх без необхідності перевизначення:
Хоча MedicalStaff абстрактний, він може мати конструктор — але він викликається лише через base(...) у похідних класах. Звернення new MedicalStaff(...) безпосередньо заборонено компілятором.
Абстрактні методи
Абстрактний клас може визначати абстрактні методи — методи без реалізації, позначені ключовим словом abstract. Вони задають контракт: кожен неабстрактний похідний клас зобов'язаний реалізувати такий метод через override. Абстрактний метод не може мати тіла — лише сигнатуру:

Абстрактні методи є частиною поліморфного інтерфейсу: виклик m.Examine() через змінну MedicalStaff завжди виконає реалізацію реального типу — так само, як і virtual + override. Різниця в тому, що abstract не має реалізації за замовчуванням і похідний клас не може відмовитись від реалізації (якщо сам не є абстрактним).
Абстрактні властивості
Крім методів, абстрактними можуть бути й властивості. Їх оголошення схоже на автовластивість, але без реального тіла — лише порожні блоки get та set:
При перевизначенні абстрактної властивості у похідному класі її можна реалізувати як повноцінну властивість з полем або як автовластивість — залежно від потреб. У прикладі вище використані вирази-тіла (=>), що повертають константу.
Відмова від реалізації в проміжному класі
Якщо похідний клас не бажає або не може реалізувати всі абстрактні члени базового — він сам повинен бути оголошений як abstract. У такому разі обов'язок реалізації переходить до його нащадків:
Клас Surgeon є проміжним абстрактним класом: він додає власну властивість SurgeryType, але не реалізує Examine() та Role. Клас CardiacSurgeon вже конкретний — і зобов'язаний реалізувати всі успадковані абстрактні члени.
abstract vs virtual: коли що обирати
abstract |
virtual |
|
|---|---|---|
| Реалізація у базовому | Відсутня | Є (за замовчуванням) |
| Похідний зобов'язаний | Так (або бути abstract) | Ні (може не перевизначати) |
| Клас має бути abstract | Так | Ні |
| Поліморфізм | Так | Так |
Правило вибору: якщо у базовому класі немає і не може бути розумної реалізації за замовчуванням — використовуйте abstract. Якщо базова реалізація має сенс, але похідні можуть її уточнити — використовуйте virtual.