OOP Course
Сьогодні

Підрозділ 3.1

Класи та об'єкти

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

3.1. Класи та об'єкти

Проблема без класів

Розглянемо типову задачу: зберегти інформацію про пацієнтів клініки та вивести її на екран. На перший погляд здається, що достатньо кількох змінних — ім'я, телефон, вік. Але що відбувається, коли пацієнтів стає більше одного?

Уже з двома пацієнтами — шість змінних. Із десятьма — шістдесят. Їх легко переплутати: ніщо не заважає випадково записати вік у змінну телефону. Передати набір пов'язаних змінних у метод — окремий виклик, адже доведеться перераховувати кожну з них як окремий параметр. Зберегти всіх пацієнтів у масив — взагалі неможливо, бо масив містить лише один тип.

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


Клас і об'єкт

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

Клас — це опис нового типу даних: він визначає, які поля (дані) та методи (поведінка) матиме кожен представник цього типу. Клас — це лише шаблон, він не займає пам'яті під конкретні дані.

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

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

Важливо також усвідомити: у системі типів C# клас — це повноцінний тип, нарівні з int, string чи bool. Після оголошення class Patient компілятор знає тип Patient і дозволяє використовувати його скрізь, де дозволено будь-який інший тип: як тип змінної, параметра методу, елемента масиву, повернення функції.

Клас Patient як шаблон та два об'єкти-екземпляри


Оголошення класу

Клас оголошується ключовим словом class, за яким слідує ім'я та тіло у фігурних дужках:

class Patient
{
    // поля та методи
}

Ім'я класу записується у стилі PascalCase — кожне слово з великої літери: Patient, DoctorManager, AppointmentStatus. Це загальноприйнята конвенція для типів у C#.

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


Поля

Поля — це змінні, оголошені безпосередньо в тілі класу. Вони зберігають стан кожного конкретного об'єкта і доступні з будь-якого методу цього класу без передачі через параметри.

class Patient
{
    public string Name  = "Невідомий";
    public string Phone = "";
    public int    Age;
}

Модифікатор public означає, що поле доступне ззовні класу — з будь-якого місця програми, де є посилання на об'єкт. Це найпростіший підхід, достатній для початку; у пізніших розділах ми побачимо, чому в реальних проєктах поля роблять private і захищають їх через властивості.

Якщо поле не ініціалізоване явно, воно отримує значення за замовчуванням відповідно до свого типу. Це не випадковий сміч із пам'яті, а гарантована поведінка середовища виконання .NET:

Зверніть увагу: прямий публічний доступ до полів (patient.Name = "...") — це найпростіший підхід для навчального прикладу. У реальних проєктах поля роблять private і надають доступ через властивості з валідацією. Ми прийдемо до цього в розділі про інкапсуляцію.


Методи

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

Усередині методу поля Name, Phone, Age доступні напряму — без будь-якого префікса. Явно вказати, що йдеться про поле саме цього об'єкта, а не про локальну змінну, можна через ключове слово this:

public void Display()
{
    // this.Name та Name — одне й те саме,
    // але this корисний коли параметр має те ж ім'я що й поле
    Console.WriteLine($"Пацієнт: {this.Name}, вік: {this.Age}");
}

Створення об'єкта

Оголошення класу — це лише опис. Щоб отримати реальний об'єкт у пам'яті, використовується оператор new:

Patient patient1 = new Patient();

У цьому рядку відбуваються три речі:

  1. new Patient() виділяє блок пам'яті в купі (heap) та ініціалізує всі поля значеннями за замовчуванням або початковими значеннями.
  2. Викликається конструктор — спеціальний метод ініціалізації (наразі автоматичний, без параметрів).
  3. Змінна patient1 отримує посилання — адресу розміщення об'єкта в пам'яті.

Починаючи з C# 9, якщо тип змінної вже вказаний зліва, його можна не повторювати в new:

Patient patient1 = new();  // рівнозначно new Patient()

Точкова нотація

Доступ до полів і методів об'єкта здійснюється через крапку (dot notation): спочатку ім'я змінної, потім крапка, потім ім'я члена.


Об'єкти у пам'яті

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

Стек (stack) — швидка область пам'яті для локальних змінних і параметрів методів. Стек працює за принципом LIFO: коли метод завершується, всі його локальні змінні автоматично зникають. Змінна-об'єкт (Patient patient1) живе саме тут, але вона зберігає не самі дані, а посилання — адресу у пам'яті, де реально знаходиться об'єкт.

Купа (heap) — велика область пам'яті для довгоживучих об'єктів. Оператор new завжди виділяє пам'ять у купі. Об'єкти живуть у купі до тих пір, поки на них є хоча б одне посилання; коли всі посилання зникають, збирач сміття (Garbage Collector) автоматично звільняє пам'ять.

Стек зберігає посилання, купа — самі об'єкти

Це пояснює два важливі факти:

  • Об'єкт є доступним з будь-якого місця програми — достатньо мати посилання на нього.
  • Локальна змінна може зникнути, але об'єкт у купі залишиться, якщо на нього ще посилаються.

Кілька об'єктів

Кожен об'єкт у купі незалежний: він зберігає власний набір значень полів. Зміна полів одного об'єкта жодним чином не впливає на інший.


Дві змінні — один об'єкт

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

Дві змінні — одне посилання на один об'єкт

Це фундаментальна відмінність між посилальними типами (class) і типами-значеннями (int, bool, struct). При присвоєнні int b = a створюється незалежна копія числа. При присвоєнні Patient b = a копіюється лише посилання, сам об'єкт залишається одним.


null — відсутнє посилання

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

Спроба викликати метод або звернутися до поля через null-посилання призводить до NullReferenceException — одного з найпоширеніших винятків у програмуванні. Саме тому перевірка на null перед використанням — обов'язкова звичка.


Масив об'єктів

Оскільки Patient — це повноцінний тип, об'єкти можна зберігати у масиві так само, як числа чи рядки. Масив Patient[] зберігає посилання на об'єкти, тому кожен елемент спочатку дорівнює null і потребує ініціалізації.

Саме цю структуру — клас і масив об'єктів — ми будемо розвивати впродовж усього курсу: додаватимемо методи пошуку, сортування, фільтрації, поступово ускладнюючи систему в міру вивчення нових інструментів мови.


Константи класу

Константи зберігають значення, що не змінюється і логічно належить всьому класу, а не конкретному об'єкту. Оголошуються з ключовим словом const, значення присвоюється лише один раз — при оголошенні.

Звернення до константи здійснюється через ім'я класу: Patient.MaxNameLength — а не через екземпляр. Це логічно: константа не залежить від конкретного об'єкта, вона є частиною самого опису типу.


Клас в окремому файлі

У реальних проєктах кожен клас розміщується у власному файлі, ім'я якого збігається з ім'ям класу: Patient.cs. Це стандартна конвенція, що спрощує навігацію у великих кодових базах.

Patient.cs

class Patient
{
    public string Name  = "Невідомий";
    public string Phone = "";
    public int    Age;

    public void Display()
    {
        Console.WriteLine($"Пацієнт: {Name}, тел: {Phone}, вік: {Age}");
    }

    public string GetShortInfo()
    {
        return $"{Name} ({Age} р.)";
    }
}

Program.cs

Patient p = new Patient();
p.Name  = "Олена Коваль";
p.Phone = "0501234567";
p.Age   = 32;
p.Display();

Обидва файли належать одному проєкту — компілятор C# автоматично бачить усі класи в усіх файлах проєкту без жодного import, include чи require. Достатньо, щоб файли знаходились у тій самій директорії проєкту або підключеній до нього.


Підсумок

Поняття Що це
class Шаблон нового типу з полями і методами
Поле Змінна на рівні класу, зберігає стан об'єкта
Метод Функція, що визначає поведінку; має доступ до полів
new Виділяє пам'ять у heap, повертає посилання
public Поле або метод доступні ззовні класу
this Явне посилання на поточний об'єкт усередині методу
const Значення належить класу, незмінне; доступ через ім'я класу
null Посилання, що не вказує на жоден об'єкт
Stack Зберігає локальні змінні і посилання
Heap Зберігає самі об'єкти; пам'ять звільняє GC

У наступному параграфі ми розглянемо конструктори — спеціальні методи, що дозволяють задавати початкові значення полів безпосередньо в момент створення об'єкта через new, а не після.

Розроблено Tomka Yurii · © 2026 ·