Professional Documents
Culture Documents
3 - 2023 - ООП - Конспект - лекція - 1 - Класи 1
3 - 2023 - ООП - Конспект - лекція - 1 - Класи 1
Описом об'єкта є клас, а об'єкт є екземпляр цього класу. Можна ще провести таку
аналогію: у нас, у всіх, є деяке уявлення про людину, яка має ім'я, вік, якісь інші
характеристики. Тобто, певний шаблон - цей шаблон можна назвати класом. Конкретне
втілення цього шаблону може відрізнятися, наприклад, одні мають одне ім'я, інші - інше
ім'я. І реально існуюча людина (фактично екземпляр даного класу) представлятиме
об'єкт цього класу.
В принципі, раніше вже використовувалися класи. Наприклад, тип string, який є рядком,
фактично є класом. Або, наприклад, клас Console, у якого метод WriteLine() виводить
до консолі деяку інформацію. Тепер подивимося, як ми можемо визначати власні
класи.
class назва_класу
{
// Вміст класу
}
Після слова class йде ім'я класу і далі у фігурних дужках йде власне вміст класу.
Наприклад, визначимо у файлі Program.cs клас Person, який представлятиме людину:
class Person
{}
Клас може зберігати деякі дані. Для зберігання даних у класі застосовуються поля.
Насправді поля класу - це змінні, визначені лише на рівні класу.
class Person
{
public string name = "Не визначено"; // ім'я
public int age; // вік
public void Print()
{
Console.WriteLine($"Ім'я: {name} Вік: {age}");
}
}
В даному випадку в класі Person визначено поле name, яке зберігає ім'я та поле age,
яке зберігає вік людини. На відміну від змінних, визначених методами, поля класу
можуть мати модифікатори, які вказуються перед полем. Так, в даному випадку, щоб усі
поля були доступні поза класом Person поля визначені модифікатором public.
Спочатку йде оператор new, що виділяє пам'ять для об'єкта, а після нього йде виклик
конструктора.
class Person
{
public string name = "Undefined";
public int age;
Для створення об'єкта Person використовується вираз new Person(). У результаті після
виконання цього висловлювання у пам'яті буде виділено ділянку, де зберігатимуться всі
дані об'єкта Person. А змінна Tom отримає посилання на створений об'єкт, і через цю
змінну ми можемо використовувати цей об'єкт і звертатися до його функціональності.
Для звернення до функціональності класу – полів, методів (а також інших елементів
класу) застосовується крапкова нотація – після об'єкта класу ставиться крапка, а потім
елемент класу:
об'єкт.поле_класу
об'єкт.метод_класу(параметри_метода)
class Person
{
public string name = "Undefined";
public int age;
Розглянемо приклад:
person.Name = "Tom";
class Person
{
private string name = "Undefined";
Тут у класі Person визначено приватне поле name, яке зберігає ім'я користувача, і є
загальнодоступна властивість Name. Хоча вони мають практично однакову назву за
винятком регістру, але це не більше, ніж стиль, назви у них можуть бути довільні і не
обов'язково повинні співпадати.
Через цю властивість ми можемо керувати доступом до змінної name. У властивості в
блоці get повертаємо значення поля:
person.Name = "Tom";
Якщо ми отримуємо значення якості, то спрацьовує блок get, який насправді повертає
значення змінної name:
Можливо, може виникнути питання, навіщо потрібні властивості, якщо ми можемо у цій
ситуації обходитися звичайними полями класу? Але властивості дозволяють вкласти
додаткову логіку, яка може бути потрібна при встановленні або отриманні значення.
Наприклад, нам треба встановити перевірку за віком:
Console.WriteLine(person.Age); // 1
person.Age = 37;
Console.WriteLine(person.Age); // 37
person.Age = -23;
Console.WriteLine(person.Age); // 37
class Person
{
int age = 1;
public int Age
{
set
{
if (value < 1 || value > 120)
Console.WriteLine("Вік має бути в діапазоні від 1 до 120");
else
age = value;
}
get { return age; }
}
}
person.Age = -23;
Console.WriteLine(person.Name); // Tom
// person.Name = "Bob"; // !
person.Age = 37;
// Console.WriteLine(person.Age); // !
person.Print();
class Person
{
string name = "Tom";
int age = 1;
Тут властивість Name доступна лише читання, оскільки вона має лише блок get:
Console.WriteLine(person.Name);
person.Name = "Bob"; // !
А властивість Age, навпаки, доступна тільки для запису, оскільки вона має лише блок
set:
person.Age = 37;
Console.WriteLine(person.Age); // !
В даному випадку клас Person має властивість Name, яка доступна лише для читання і
яка повертає загальне значення на основі значень змінних firstName та lastName.
//tom.Name = "Bob"; // !
Console.WriteLine(tom.Name); // Tom
class Person
{
string name = "";
public string Name
{
get { return name; }
Тепер закритий блок set ми зможемо використовувати тільки в даному класі – у його
методах, властивостях, конструкторі, але ніяк не в іншому класі:
При використанні модифікаторів у властивостях слід враховувати низку обмежень
● Модифікатор для блоку set або get можна встановити, якщо властивість має
обидва блоки (і set, і get)
● Тільки один блок set або get може мати модифікатор доступу, але не обидва
відразу
● Модифікатор доступу блоку set або get повинен бути більшим, ніж модифікатор
доступу властивості. Наприклад, якщо властивість має модифікатор public, то
блок set/get може мати тільки модифікатори protected internal, internal, protected,
private protected та private
Властивості керують доступом до полів класу. Однак якщо у нас з десяток і більше
полів, то визначати кожне поле і писати для нього однотипну властивість було б
стомлюючим. Тому в .NET було додано автоматичні властивості. Вони мають
скорочене оголошення:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
Console.WriteLine(tom.Name); // Tom
Console.WriteLine(tom.Age); // 37
class Person
{
public string Name { get; set; } = "Tom";
public int Age { get; set; } = 37;
}
class Person
{
public string Name { private set; get;}
public Person(string name) => Name = name;
}
Ми можемо прибрати блок set і зробити автовластивість доступною тільки для читання.
В цьому випадку для зберігання значення цієї властивості для нього неявно буде
створюватися поле з модифікатором readonly, тому слід враховувати, що подібні
get-властивості можна встановити або з конструктора класу, як у прикладі вище, або
при ініціалізації якості:
class Person
{
public string Name { get; } = "Tom";
public Person(string name) => Name = name;
}
Крім полів та властивостей клас може визначати для зберігання даних константи. На
відміну від полів значення встановлюється один раз безпосередньо при їх оголошенні і
згодом не може бути змінено. Крім того, константи зберігають деякі дані, які відносяться
не до одного об'єкта, а до всього класу загалом. І для звернення до константів
застосовується ім'я об'єкта, а ім'я класу:
Console.WriteLine(Person.type); // Person
// Person.type = "User"; // !
class Person
{
public const string type = "Person";
public string name = "Undefined";
public int age;
public void Print() => Console.WriteLine($"{type}: {name} - {age}");
}
Тут у класі Person визначено константу type, яка зберігає назву класу:
Назва класу залежить від об'єкта. Ми можемо створити багато об'єктів Person, але
назва класу від цього не повинна змінитись - вона відноситься до всіх об'єктів Person і
не повинна змінюватися. Тому назву типу можна зберегти як константи.
Варто зазначити, що константі відразу при її визначенні необхідно надати значення.
Подібно до звичайних полів ми можемо звертатися до константів класу всередині цього
класу. Наприклад, у методі Print значення константи виводиться на консоль.
Однак якщо ми хочемо звернутися до константи поза її класом, то для звернення
необхідно використовувати ім'я класу:
Console.WriteLine(Person.type); // Person
tom.Print();
class Person
{
public string name;
public int age;
public Person()
{
Console.WriteLine("Person");
name = "Tom";
age = 37;
}
public void Print()
{
Console.WriteLine($"Name: {name} Age: {age}");
}
}
public Person()
{
Console.WriteLine("Person");
name = "Tom";
age = 37;
}
tom.Print();
bob.Print();
sam.Print();
class Person
{
public string name;
public int age;
public Person() { name = "Неизвестно"; age = 18; } // 1
конструктор
public Person(string n) { name = n; age = 18; } // 2
конструктор
public Person(string n, int a) { name = n; age = a; } // 3
конструктор
Тепер у класі визначено три конструктори, кожен з яких набуває різної кількості
параметрів та встановлює значення полів класу. І ми можемо викликати один із цих
конструкторів для створення об'єкта класу.
class Person
{
public string name;
public int age;
public Person() { name = "Unk"; age = 18; }
public Person(string name) { this.name = name; age = 18; }
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void Print() => Console.WriteLine($"Name: {name} Age: {age}");
}
this.name = name;
class Person
{
public string name;
public int age;
public Person() : this("Неизвестно")
{ }
public Person(string name) : this(name, 18)
{ }
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void Print() => Console.WriteLine($"Name: {name} Age: {age}");
}
tom.Print();
bob.Print();
sam.Print();
class Person
{
public string name;
public int age;
public Person(string name = "Unk", int age = 18)
{
this.name = name;
this.age = age;
}
public void Print() => Console.WriteLine($"Name: {name} Age: {age}");
}
class Person
{
public string name;
public Company company;
public Person()
{
name = "Undefined";
company = new Company();
}
public void Print() => Console.WriteLine($"Name: {name} Company:
{company.title}");
}
class Company
{
public string title = "Unk";
}
class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
Console.WriteLine(name); // Tom
Console.WriteLine(age); // 33
При отриманні значень декоструктора нам необхідно надати стільки змінних, скільки
деконструктор повертає значень. Проте, буває, що не всі ці значення потрібні. І замість
повертаються значень ми можемо використовувати прочерк _. Наприклад, нам треба
отримати лише вік користувача:
Console.WriteLine(age); // 33
Створити клас із ім'ям Address. У тілі класу потрібно створити поля: index, country, city,
street, house, apartment. Для кожного поля створити властивість з двома методами
доступу.
Створити клас Employee. У тілі класу створити власний конструктор, який приймає два
рядкові аргументи, і ініціалізує поля, що відповідають прізвищу та імені співробітника.
Створити метод, що розраховує оклад співробітника (залежно від посади та стажу) та
податковий збір. Написати програму, яка виводить на екран інформацію про
співробітника (прізвище, ім'я, посада), оклад та податковий збір.
Створити клас User, що містить інформацію про користувача (логін, ім'я, прізвище, вік,
дату заповнення анкети). Поле “дата заповнення анкети” має бути проініціалізоване
лише один раз (при створенні екземпляра цього класу) без можливості його подальшої
зміни. Реалізуйте виведення на екран інформації про користувача.