- •Мови програмування. Представлення даних.
- •1. Вступ. Про обчислювальну техніку.
- •2. Історія мов програмування.
- •3. Поняття про платформу .Net
- •4. Створення мови програмування с#.
- •5. Представлення даних. Необхідність типізації. Двійкова арифметика.
- •6. Основні поняття програмування.
- •Поняття про інтегроване середовище розробки VisualStudio (на прикладі Visual Studio 2005). Структура c#-програми.
- •1. Основні можливості інтегрованого середовища розробки VisualStudio .Net.
- •2. Структура програми мовою с#.
- •Int I; // Визначили цілу змінну
- •Основні елементи мови с#.
- •1. Основні вбудовані типи мови с#
- •2. Визначення та ініціалізація змінних, область їх видимості.
- •3. Приведення типів.
- •Інакше обидва операнди перетворюються до типу int;
- •4. Літерали (константи) мови с#.
- •5. Операції мови с#.
- •5.1. Арифметичні операції.
- •5.2. Операції інкременту та декременту.
- •5.3. Операції відношення (порівняння).
- •5.4. Логічні операції.
- •5.5. Порозрядні (бітові) операції.
- •5.6. Умовна (тернарна) операція.
- •5.7. Операції присвоєння.
- •5.8. Пріоритет операцій.
- •Основні інструкції керування мови с# – розгалуження та цикли.
- •1. Розгалуження у мові с#
- •2. Цикли у мові с#
- •2.1. Цикл for.
- •2.2. Цикл while.
- •2.3. Цикл do-while.
- •3. Керування виходом із циклів с#
- •Масиви в мові с#.
- •1. Визначення та ініціалізація масиву.
- •2. Цикл foreach
- •3. Багатовимірні масиви.
- •4. Використання деяких методів класу System.Array.
- •5. Масиви масивів. Непрямокутні масиви.
- •Структуровані типи даних (колекції) в мові c#
- •1. Основні структури даних та їх призначення
- •2. Використання списку ArrayList та узагальненого списку List
- •3. Використання асоційованого списку Hashtable та узагальненого словника Dictionary
- •Класи в мові с#.
- •1. Визначення класу.
- •2. Методи класу.
- •3. Методи з параметрами.
- •4. Конструктор класу.
- •Методи в мові с#.
- •1. Передача об’єктів методам.
- •2. Використання модифікаторів для параметрів методів.
- •3. Методи, що повертають об’єкти.
- •Перевантаження методів в мові с#.
- •1. Перевантаження методів.
- •2. Перевантаження конструкторів.
- •3. Використання ключового слова this.
- •4. Деструктор класу.
- •5. Метод Main ().
- •Статичні члени класу.
- •1. Статичні дані-члени класу.
- •2. Статичні методи-члени класу.
- •3. Статичний конструктор класу.
- •4. Статичні класи, локалізація та глобалізація
- •Властивості та індексатори.
- •1. Властивості.
- •2. Індексатори.
- •Спадкування в мові с#.
- •1. Поняття про спадкування та ієрархію класів.
- •2. Спадкування та правила доступу до членів класів.
- •3. Конструктори базового та похідних класів.
- •4. Посилання на екземпляри базового та похідних класів.
- •5. Поняття про поліморфізм.
- •6. Віртуальні функції – більш детальний погляд.
- •7. Абстрактні методи та класи.
- •Перевантаження операцій в мові с#.
- •1. Загальні відомості.
- •2. Перевантаження бінарних арифметичних операцій.
- •3. Перевантаження унарних операцій.
- •4. Перевантаження операцій відношення.
- •5. Перевантаження логічних операцій.
- •6. Підсумкові зауваження.
- •Структури та переліки в мові с#.
- •1. Структури.
- •2. Переліки.
- •Делегати, події та обробники подій
- •1. Делегати (delegate).
- •2. Події та їх обробники.
- •Атрибути та їх використання
- •Рекомендована література
2. Спадкування та правила доступу до членів класів.
З’ясуємо, що відбувається при спадкуванні із закритими (private) членами базового класу. Нагадаємо, що використання закритих членів класу – одна з основ інкапсуляції даних. При спадкуванні закриті члени класу залишаються недоступними для похідних класів. Такий підхід зрозумілий, адже в іншому разі для «зламу» закритих членів класу досить було б утворити похідний від нього клас. Переконайтесь самостійно, що якщо у базовий клас Building включити закрите поле, наприклад, private double cost; то при спробі звернутись до нього із екземпляру похідного класу, вказавши lb.cost, одержимо синтаксичну помилку:
«… is inaccessible due to its protection level» – недоступний із-за його рівня захисту.
Проте, у випадках, коли необхідно дозволити похідним класам використовувати закриті поля базового класу, останні можна визначити із модифікатором доступу protected – захищений. Такий член класу відкритий лише у своїй ієрархії класу і закритий для інших частин програми.
У наступному прикладі в базовому класі Base визначені: захищене (protected) поле field та відкрита властивість Field, яка керує доступом до цього поля (адже у функції Main(), зокрема, неможливо звернутись до поля field безпосередньо). У похідному класі SubBase створимо метод ChangeField(), призначення якого – змінити (в даному прикладі подвоїти) захищене поле field базового класу Base.
using System;
namespace ProtectedClass
{
class Base
{
protected int field;
public int Field
{
get { return field; }
set { field = value; }
}
}
class SubBase : Base
{
public void ChangeField()
{ // Метод має доступ до захищеного поля базового класу
field = 2 * field;
}
}
class Program
{
static void Main()
{
Base b = new Base();
b.Field = 100;
Console.WriteLine("Клас Base: Field = {0}", b.Field);
SubBase sb = new SubBase();
sb.Field = 200;
Console.WriteLine(
"Клас SubBase: Field = {0}", sb.Field);
// Метод змінює захищене поля базового класу
sb.ChangeField();
Console.WriteLine("Клас SubBase пiсля ChangeField() :
Field = {0}", sb.Field);
}
}
}
Після запуску проекту на екрані побачимо наступні повідомлення:
Клас Base: Field = 100
Клас SubBase: Field = 200
Клас SubBase пiсля ChangeField() : Field = 400
Таким чином, похідні класи мають відкритий доступ до захищених членів базового класу. Проте для інших частин коду поле field у екземплярах похідних класів залишається, як і раніше, недоступним.
3. Конструктори базового та похідних класів.
Як відомо, конструктори відіграють важливу роль при створенні об’єктів. Навіть, якщо у класі конструктор не визначений, компілятор створює конструктор за замовчуванням, який присвоює нульові значення всім полям. Важливо зрозуміти, що при створенні екземпляру похідного класу недостатньо роботи лише конструктору цього класу, адже він несе відповідальність тільки за члени похідного класу, який у свою чергу містить всі члени свого базового класу. Отже, необхідно визначити спочатку всі значення полів базового класу. Тому при створенні екземпляру похідного класу компілятором спочатку викликається конструктор базового класу і лише потім конструктор похідного класу. Наступний простий приклад наочно демонструє порядок виклику конструкторів базового та похідних класів.
using System;
namespace InheritanceConstructor
{
class Base // базовий клас
{
public Base()
{
Console.WriteLine(
"Cтворюємо екземпляр базового класу");
}
}
class SubBase : Base // похідний клас
{
public SubBase()
{
Console.WriteLine("Cтворюємо екземпляр похiдного класу");
}
}
class SubSubBase : SubBase // похідний від похідного класу
{
public SubSubBase()
{
Console.WriteLine(
"Cтворюємо екземпляр похiдного вiд похiдного класу");
}
}
class Program
{
static void Main()
{
Base b = new Base();
Console.WriteLine("----------------------");
SubBase sb = new SubBase();
Console.WriteLine("----------------------");
SubSubBase ssb = new SubSubBase();
}
}
}
На екрані одержимо наступні повідомлення:
Cтворюємо екземпляр базового класу
----------------------
Cтворюємо екземпляр базового класу
Cтворюємо екземпляр похiдного класу
----------------------
Cтворюємо екземпляр базового класу
Cтворюємо екземпляр похiдного класу
Cтворюємо екземпляр похiдного вiд похiдного класу
Як бачимо, при створенні екземпляру найнижчого в ієрархії класу послідовно спрацьовують всі конструктори, починаючи від конструктору базового класу. Спробуємо змінити визначення базового класу Base, додавши в нього деяке приватне поле та конструктор з параметром для його ініціалізації:
class Base // базовий клас
{
private int field ;
// конструктор ініціалізує поле field
public Base(int field_)
{
field = field_;
Console.WriteLine(
"Cтворюємо екземпляр базового класу field = {0}", field);
}
}
Спроба скомпілювати цей приклад призведе до помилки «No overload for method 'Base' takes '0' arguments» – немає перевантаженого конструктора 'Base' без аргументів. Поява такого повідомлення компілятора цілком зрозуміла, адже конструктор похідного класу SubBase автоматично намагається викликати конструктор класу Base без параметрів, а клас Base такого конструктору не надає. Можливих виходів із такої ситуації існує декілька. Один із варіантів – створити у класі Base конструктор без параметрів, використавши уже знайомий нам синтаксис виклику одним конструктором класу іншого:
public Base() : this (1) { }
Правда, в цьому випадку прийдеться задовольнитись викликом конструктору із деяким значенням параметру за замовчуванням, в даному прикладі це 1.
Інший варіант – викликати у похідному класі конструктор базового класу, передавши йому потрібні значення аргументів. Для цього використовується наступний синтаксис:
<специфікатор_доступу> <ідентифікатор_конструктора_похідного_класу>
(<список_параметрів_конструктора_похідного_класу >) :
base (<список_параметрів_конструктора_базового_класу>)
{
// код конструктора похідного класу
}
Внесемо такі зміни у наш приклад.
using System;
namespace InheritanceConstructor
{
class Base // базовий клас
{
private int field ;
// конструктор ініціалізує поле field
public Base(int field_)
{
field = field_;
Console.WriteLine("Cтворюємо екземпляр базового класу
field = {0}", field);
}
}
class SubBase : Base // похідний клас
{
// виклик конструктору базового класу
public SubBase(int field_) : base(field_)
{
Console.WriteLine(
"Cтворюємо екземпляр похiдного класу");
}
}
// похідний клас від похідного класу
class SubSubBase : SubBase
{
public SubSubBase(int field_) : base(field_)
{
Console.WriteLine(
"Cтворюємо екземпляр похiдного вiд похiдного класу");
}
}
class Program
{
static void Main()
{
Base b = new Base(100);
Console.WriteLine("-------------------------");
SubBase sb = new SubBase(200);
Console.WriteLine("-------------------------");
SubSubBase ssb = new SubSubBase(300);
}
}
}
Тепер кожний похідний клас звертається не до конструктора базового класу, передаючи йому свій аргумент. Результатом роботи будуть наступні повідомлення:
Cтворюємо екземпляр базового класу field = 100
-------------------------
Cтворюємо екземпляр базового класу field = 200
Cтворюємо екземпляр похiдного класу
-------------------------
Cтворюємо екземпляр базового класу field = 300
Cтворюємо екземпляр похiдного класу
Cтворюємо екземпляр похiдного вiд похiдного класу
Використання службового слова base в такому контексті дозволяє викликати будь-який із перевантажених конструкторів базового класу відповідно до списку аргументів виклику.
Зауваження. Важливо розуміти також, що якщо конструктор деякого класу визначений із модифікатором private, звертання до нього у похідному класі неможливо, тобто від такого класу неможливо створити екземпляр похідного.