
Об’єктно-орієнтоване програмування
Лабораторна робота № 2
Структури
Мета та завдання: ознайомитися з структурами, як окремим випадком класу, що дозволяє задавати розгорнутий тип даних; розглянути відмінності посилальних і розгорнених типів даних; навчитися – коли і де слід застосовувати той або інший тип – вибирати структуру або посилальний клас.
Теоретичні відомості
Розгорнені і посилальні типи
У ООП головна роль, яку грають класи, полягає в заданні типу даних. Хоча слід пам'ятати, що деякі класи можуть грати тільки одну роль – роль модуля, і для них неможливо створювати об'єкти.
Отже, розглянемо класи, що задають тип даних. Такий клас Т представляє опис безлічі об'єктів – екземплярів класу, задаючи їх властивості і поведінку. Якщо класом є текст – статичний опис, то об'єкти класу створюються динамічно в процесі роботи програми. Як правило, об'єкти класу Т створюються в інших класах, що є клієнтами класу Т. Розглянемо в клієнтському класі оголошення об'єкту класу T, виконане з ініціалізацією:
T x = new T();
Нагадаю, як виконується цей оператор, що створює об'єкт класу Т. Об'ектам потрібна пам'ять, щоб з ними можна було працювати. Розглянемо дві класичні стратегії виділення пам'яті і скріплення об'єкту, що створюється в пам'яті, і об’єкту, оголошенійому в тексті. Є два типи пам'яті – стек ( stack ) і купа ( heap ). Об’єкту x в стеку завжди відводиться пам'ять, але яка пам'ять – залежить від того, до розгорненого або посилального типу відноситься клас Т.
Означення 1.Якщо, клас T відноситься до розгорненого типу, то в стеку об’єкту x відводиться пам'ять, необхідна об'єкту класу T. Говорять, що об'єкт розгортається на пам'яті, жорстко пов'язаній з об’єктом x. Цю пам'ять об’єкт x ні з ким не розділяє.
Означення 2.Якщо, клас T відноситься до посилального типу, то пам'ять об'єкту відводиться в купі, а в стеку об’єкту x відводиться додаткова пам'ять, що містить посилання на об'єкт.
Для розгорненого типу характерне те, що кожен об’єкт ні з ким не розділяє свою пам'ять; об’єкт жорстко зв'язується зі своїм об'єктом. В цьому випадку об’єкт і об'єкт можна і не розрізняти, вони стають неподільним поняттям. Для посилальних типів ситуація інша – декілька об’єктів можуть посилатися на один і той же об'єкт. Такий об’єкт розділяє пам'ять і є різними іменами одного об'єкту. Корисно розуміти різницю між об’єктом, заданим посиланням, і об'єктом, на який у нинішній момент указує посилання. Відмітимо, що тип об'єкту в купі може не співпадати з базовим типом об’єкту, заданим класом T. Більш того, типи об'єктів, з якими динамічно зв'язується об’єкт, можуть бути різними, хоча і потрібне певне узгодження типів. Докладніше ці питання обговорюватимуться при розгляді наслідування.
Розгорнені і посилальні типи породжують дві різні семантики. Розглянемо привласнення:
y = x;
Коли об’єкт у належить розгорненому типу, значення полів об'єкту, пов'язаного з об’єктом у, при привласненні змінюються, набуваючи значень полів об'єкту, пов'язаного з x. Нагадаємо, що поля у зберігаються в стеку.
Коли об’єкт у належить посилальному типу, відбувається привласнення посилань. Посилання у набуває значення посилання x, і обидва вони, після привласнення указують на один і той же об'єкт. Об'єкт в купі, на який до привласнення указувало посилання у, втрачає одне зі своїх посилань і, можливо, стає "висячим" об'єктом без посилань, стаючи здобиччю для складальника сміття.
Розглянемо операцію перевірки об'єктів на еквівалентність:
if (x == у)
Для розгорнених типів об'єкти x і у еквівалентні, якщо еквівалентні значення всіх їх полів. Для посилальних типів об'єкти x і у еквівалентні, якщо еквівалентні значення посилань.
Мова програмування повинна дозволяти програмісту у момент визначення класу вказати, до розгорненого або посилального типу відноситься клас. У мові C# це робиться таким чином. Якщо оголошення класу задається з використанням службового слова class, то такий клас відноситься до посилальних типів.
public class A { }
Якщо, оголошення класу задається з використанням службового слова struct, то такий клас відноситься до розгорнених типів, які також називають значущими типами або value типами.
public struct B { }
Нагадаємо: до значущих типів відносяться всі вбудовані арифметичні типи, булевий тип, перерахування, структури. До посилальних типів відносяться масиви, рядки, класи. Чи можна в C# спроектувати свій власний клас так, щоб він відносився до значущих типів? Відповідь на це питання – позитивна , хоча і з рядом обмовок. Для того, щоб клас віднести до значущих типів, його досить оголосити як структуру.