C++/Об'єктно-орієнтовне програмування/Структури

Матеріал з Вікіпідручника
< C++

Структури[ред.]

Структура це складений тип даних, що містить різних членів відмінних типів. Доступ до її членів здійснюється за іменами. Значенням, що відповідає структурному об'єкту є набір значень всіх її членів, що відносяться до об'єкту. Структуру можна розглядати як спрощену реалізацію парадигми об'єкту із ООП. Структура (struct) подібна класу (class) крім визначеного довільного доступу до її членів (клас має модифікатор доступу за замовчуванням private, структура має за замовчуванням публічний доступ - public). C++ також гарантує, що структура містить лише типи визначені в C, що є еквівалентне такій самі структурі в C, таким чином дозволяючи мати зворотню сумісність і доступ до успадкованих із мови C функцій, вона також може (а може і не) містити конструктори (і повинна містити конструктори обов'язково, якщо в середині структури struct використано шаблонний клас), як і для класів компілятор неявним чином оголошує деструктор, якщо структура не має деструктора оголошеного користувачем. Структури також дозволяють виконувати Перевантаження_операторів.

Структура визначається як:

struct myStructType /*: наслідування */ {
public: 
 // оголошення публічних членів
protected:
 // оголошення захищених членів
private:
 // оголошення приватних членів
};

Не обов'язкові у використанні ключові слова public:, protected:, private: визначають статус захищеності доступу до відповідних членів структури, що вказані за ними. Їх можна вказувати у будь-якій послідовності, і може зустрічатися більше ніж одне унікальне входження таких ключових слів. Якщо жодного статусу захисту не вказано, тоді за замовчуванням члени структури матимуть доступ public. (До членів структури із доступом private або protected можуть доступатися або методи або "друзі" даної структури).

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

Об'єкти (екземпляри) структури типу myStructType оголошуються наступним чином:

 /* struct */ myStructType obj1 /* , obj2, ... */;

Повторювання ключового слова struct на початку не є обов'язковим.

Об'єкти структури можна визначати прямо після визначення структури замість того, щоб використовувати ім'я структури в якості типу структури:

 struct { /*members*/ } obj1 /*, obj2, .. */ ;
Коли потрібо використовувати структури, а не класи?

В більш старших мовах програмування використовували подібний тип даних, що називався Record (наприклад в COBOL, FORTRAN), який був реалізований в мові C за допомогою ключового слова struct. І тому C++ використовує структури аби взаємодіяти із цим успадкованим типом із мови C (уже створеним кодом). Структури простіші у роботі для програмістів і компіляторів. Структури struct краще використовувати для (старих пласких типів даних), що не мають пов'язаних методів і всі члени яких мають публічний доступ public.

Приклади[ред.]

Об'єкти точок

Як простий приклад об'єднання даних у структуру можна розглянути поняття математичної точки. В деякій абстракції, точка це два числа (координати) до яких ми ставимося як до сукупності, тобто як до єдиного об'єкту. В математичній нотації, точки часто записують у дужках, із координатами розділеними комою. Наприклад, (0, 0) позначає початок координат, а (x, y) позначає одиниці координат по осі x і по осі y від початку.

Природнім способом визначення точки є задати два числа типу double. Структура (struct) є одним із способів згрупувати ці два числа у єдиний складений об'єкт.

// Визначення структури:
 struct Point { double x, y; };

Це визначення задає структуру, яка містить два члени, що мають імена x і y. Ці члени також називають змінними екземпляру.

Типовою помилкою написання коду є забути вказати крапку з комою в кінці визначення структури. Може здаватися не звично ставити крапку із комою після закритої фігурної дужки. Цей синтаксис залишає місце для визначення екземплярів структури після її оголошення.

Оскільки ви визначили нову структуру, ви можете створити змінні даного типу:

struct Point blank; 
blank.x = 3.0; 
blank.y = 4.0;

Перший рядок схожий на традиційне визначення змінної: змінна blank має тип даних Point. Наступні два рядки ініціалізують змінні структури. Для доступу до членів структури використовується "нотація із точкою".

Доступ до змінних екземпляру

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

double x = blank.x;

Вираз blank.x буквально означає "іди знайди об'єкт із іменем blank і дістань значення члена із іменем x." В даному випадку ми запишемо її значення у змінну, що має ім'я x. Зауважте, що ніякого конфлікту імен між локальною змінною із іменем x і змінною екземпляра структури із іменем x немає. Призначенням нотації із точкою є точне визначення і віднесення змінної до відповідної структури.

Цю нотацію можна використовувати у будь-якому виразі, тому наступний вираз також є вірним.

cout << blank.x << ", " << blank.y << endl; 
double distance = sqrt(blank.x * blank.x + blank.y * blank.y);

Результатом першого рядка буде вивід 3, 4; а в другому рядку буде розраховане значення 5.

Операції над структурами

Більшість операцій, що використовуються над іншими типами, такі як математичні оператори ( +, %, та ін.) і оператори порівняння (==, >, та ін.), не застосовуються до структур. Насправді можна визначити значення цих операторів для нового типу, але в даному розділі це не розглядається.

З іншого боку для структур актуальним є оператор присвоювання. Він може використовуватися двома шляхами: для ініціалізації значень змінних структури і для копіювання значень від однієї структури до іншої. Ініціалізація змінних виглядає наступним чином:

Point blank = { 3.0, 4.0 };

Значення задані у фігурних дужках будуть скопійовані у змінні полів структури по черзі, в тому порядку як вони оголошені в структурі. То ж у випадку із нашим прикладом, x отримає перше значення, а y отримає друге значення.

Цей синтаксис можна використовувати лише в ініціалізації, але не в виразах із присвоюванням. Таким чином, наступний вираз є невірним.

Point blank; 
blank = { 3.0, 4.0 }; // НЕ ВІРНО !!

З іншого боку, можна задати значення однієї структури іній структурі. Наприклад:

Point p1 = { 3.0, 4.0 }; 
Point p2 = p1; 
cout << p2.x << ", " <<  p2.y << endl;

Результатом роботи цієї програми буде 3, 4.

Структури як аргументи функцій і тип результату

Синтаксис дозволяє створювати функції, що приймають структури як аргументи або можуть повертати структури. Наприклад, функція findCenter приймає як аргумент структуру Rectangle і повертає структуру Point, що містить координати центра даного Rectangle (прямокутника):

struct Rectangle {
  Point corner;
  double width, height;
};

Point findCenter (const Rectangle& box) 
{ 
  double x = box.corner.x + box.width/2; 
  double y = box.corner.y + box.height/2; 
  Point result = {x, y}; 
  return result; 
}

Для виклику цієї функції, необхідно передати змінну типу Rectangle в якості аргумента, і присвоїти значення, що буде повертатися із функції у змінну типу Point:

Rectangle mybox = { {10.0, 0.0}, 100, 200 }; 
Point center = findCenter (mybox); 
printPoint (center);

Результат цієї програми буде: (60, 100).

Зверніть увагу, що змінна типу Rectangle була передана у функцію findCenter за посиланням, оскільки це більш ефективний метод ніж копіювати всю структуру у пам'яті, що відбувалося б при передачі цієї змінної за значенням. Посилання оголошене із ключовим словом constant, що означає, що функція findCenter не буде змінювати значення аргументу box, повідомляючи, що змінна mybox, того коду що викликає функцію залишиться не змінною.

Вказівники і структури

На структури також можуть вказувати вказівники і структури самі можуть містити вказівники. Правила їх використання будуть аналогічними як для будь-яких інших фундаментальних типів даних. Вказівник має бути визначений як вказівник на структуру.

Вкладені структури[ред.]

Структури також можуть бути вкладені, таким чином що елементом структури може бути інша структура.

//Звісно ви повинні спочатку визначити структуру Point, яка не вказана у прикладі!

struct Rectangle {
 Point upper_left; 
 Point upper_right;
 Point lower_left;
 Point lower_right;
};