- •Мови програмування. Представлення даних.
- •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. Події та їх обробники.
- •Атрибути та їх використання
- •Рекомендована література
4. Посилання на екземпляри базового та похідних класів.
Важливо пам’ятати, що ідентифікатор, який ми вказуємо при визначенні екземпляру класу, є змінною-посиланням на область пам’яті, де буде розміщений об’єкт. Раніше ми використовували приведення типів при використанні змінних скалярних типів. Ці дії керувались низкою правил «просування по сходинках типів». З’ясуємо, як відбувається приведення типів при використанні посилань на екземпляри базового та похідних класів. Головне правило, яке тут діє, полягає у тому, що посиланню на базовий клас можна присвоїти посилання на будь-який похідний від нього клас. Тобто, якщо розглянути два класи – клас A та похідний від нього клас B, то правильність визначень та присвоєнь, виконаних у функції Main(), позначена у коментарях:
class A // базовий клас
{
// визначення базового класу
}
class B : A // похідний клас
{
// визначення похідного класу
}
static void Main()
{
A a = new A(); // вірно
A ab = new B(); // вірно – посиланню на базовий клас
// присвоєне посилання на похідний
B b = new B(); // вірно
B ba = new A(); // помилка – посиланню на похідний
// клас присвоєне посилання на базовий
a = b; // вірно – посиланню на базовий клас
// присвоєне посилання на похідний
b = a; // помилка – посиланню на похідний
// клас присвоєне посилання на базовий
ab = b; // вірно
b = (B) ab; // вірно, явне приведеня
b = (B) a; // вірно, явне приведеня
a = (A) b; // вірно, явне приведеня
}
Дуже важливо розуміти, що саме тип змінної-посилання на клас, визначає доступні для використання члени класу. Тобто якщо змінній ab типу A присвоєне посилання на об’єкт B , як це зроблено в інструкції
A ab = new B(); то ab є змінною-посиланням на клас A, тому через ab доступні лише члени класу A, адже змінній базового класу невідомий склад похідних класів. Для більш прозорого розуміння цього факту розглянемо ще один приклад – варіацію на тему класів Base, SubBase та SubSubBase. Тут у кожний із класів даної ієрархії включене відкрите поле, щоб мати змогу прослідкувати за їх доступністю при використанні посилань на об’єкти даної ієрархії класів. Метод fun() перевантажений тричі – він приймає відповідно параметри типів Base, SubBase та SubSubBase. Результат цього прикладу підтверджує, що змінна b має тип Base, незважаючи на створення операцією new SubBase(200) , а змінна sb має тип SubBase, незважаючи на створення операцією new SubSubBase(300).
using System;
namespace ConvertObject
{
class Base // базовий клас
{
public int field;
public Base(int field_) // конструктор
{ field = field_; }
}
class SubBase : Base // похідний клас
{
public int subfield;
public SubBase(int field_) : base(field_)
{ subfield = field_; }
}
// похідний клас від похідного класу
class SubSubBase : SubBase
{
public int subsubfield;
public SubSubBase(int field_) : base(field_)
{ subsubfield = field_; }
}
class Program
{
static void fun(Base b)
{
Console.WriteLine("об\'єкт Base: field = {0}",b.field);
}
static void fun(SubBase b)
{
Console.WriteLine( "об\'єкт SubBase: field = {0}
subfield = {1}", b.field, b.subfield);
}
static void fun(SubSubBase b)
{
Console.WriteLine("об\'єкт SubSubBase: field = {0}
subfield = {1} subsubfield = {2}", b.field,
b.subfield, b.subsubfield);
}
static void Main(string[] args)
{
object o = new Base(100); // вірно - Base «Є» object
Base b = new SubBase(200); // вірно - SubBase «Є» Base
// вірно - SubSubBase «Є» SubBase
SubBase sb = new SubSubBase(300);
SubSubBase ssb = new SubSubBase(400); // вірно
// SubSubBase ssb = new Base(1000); // тут буде помилка
fun(b);
fun(sb);
fun(ssb);
}
}
}
В результаті роботи даного прикладу одержимо наступні повідомлення:
об'єкт Base: field = 200
об'єкт SubBase: field = 300 subfield = 300
об'єкт SubSubBase: field = 400 subfield = 400 subsubfield = 400
Цікаво також перевірити, що буде, якщо закрити коментарем метод fun(SubBase b), а потім і fun(SubSubBase b). Перевірте самостійно, яким чином будуть викликатись методи fun() .