Типи даних, визначені користувачем C
Статті про IT, програмування, політику, економіку, життя та вивчення наукових дисциплін
Типи даних, визначені користувачем C++
У реальних завданнях інформація, яку потрібно обробляти, може мати складну структуру. Для адекватного її подання використовуються типи даних, побудовані на основі простих типів даних, масивів і покажчиків. Мова C++ дозволяє програмісту визначати свої типи даних та правила роботи з ними. Історично для таких типів склалося найменування, винесені у назву статті, хоча правильніше було б назвати їх типами, які визначаються програмістом.
Перейменування типів (typedef)
Для того, щоб зробити програму більш ясною, можна задати типу нове ім'я за допомогою ключового слова typedef:
typedef тип нове_ім'я [розмірність];
У разі квадратні дужки є елементом синтаксису. Розмірність може бути відсутнім. Приклади:
typedef unsigned int UINT; typedef char Msg [100]; typedef struct < char f1o [30]; int date, code; double salary; > Worker;
Введене таким чином ім'я можна використовувати так само, як і імена стандартних типів:
UINT i, j; // два змінних типу unsigned int Msg str [10]; // масив з 10 рядків по 100 символів Worker staff [100]; // масив із 100 структур
Крім завдання типів з довгими описами більш коротких псевдопімів, typedef використовується для полегшення переносимості програм: якщо машинно-залежні типи оголосити за допомогою операторів typedef, при переносі програми потрібно внести зміни лише до цих операторів.
Перерахування (enum)
При написанні програм часто виникає потреба визначити кілька іменованихконстант, котрим потрібно, щоб усі вони мали різні значення (при цьому конкретні значення можуть бути не важливими). Для цього зручно скористатися типом даних, що перераховується, всі можливі значення якого задаються списком цілих констант. Формат:
Ім'я типу задається у тому випадку, якщо програма потребує визначення змінних цього типу. Компілятор забезпечує, щоб ці змінні набирали значення лише зі списку констант. Константи повинні бути цілими і можуть ініціалізуватися звичайним чином. За відсутності ініціалізації перша константа обнулюється, а кожній наступній присвоюється на одиницю більше значення, ніж попередньої:
enum Err < ERR__READ, ERR__WRITE, ERR_CONVERT >; Err error; switch (error) < case ERR_READ : /* оператори */ break; case ERR_WRITE : /* оператори */ break; case ERR_CONVERT : /* оператори */ break; >
Константам ERR_READ, ERR_WRITE, ERR_CONVERT присвоюються значення 0, 1 та 2 відповідно.
Константам three і four надаються значення 3 і 4, константі eleven - 11.
Імена перерахованих констант мають бути унікальними, а значення можуть збігатися. Перевага застосування перерахування перед описом іменованих констант і директивою #define у тому, що пов'язані константи наочніше; крім того, компілятор при ініціалізації констант може перевірити типи.
За виконання арифметичних операцій перерахування перетворюються на цілі. Оскільки переліки є типами, які визначають користувач, для них можна вводити власні операції.
Структури (struct)
На відміну від масиву, всі елементи якого є однотипними, структура може містити елементи різних типів. У мові C++ структура є видомкласу і має всі його властивості, але в багатьох випадках достатньо використовувати структури так, як вони визначені в мові С:
struct [ ім'я_типу ] < тип_1 елемент_1 : тип_2 елемент_2; тип_n елемент_n; > [список_описувачів];
Елементи структури називаються полями структури і може мати будь-який тип, крім типу цієї структури, але може бути покажчиками нею. Якщо відсутнє ім'я типу, має бути вказано список описників змінних, покажчиків чи масивів. У цьому випадку опис структури є визначенням елементів цього списку:
// Визначення масиву структур та покажчика на структуру: struct < char f1o [30]; int date, code; double salary; > staff [100], *ps;
Якщо список відсутній, опис структури визначає новий тип, ім'я якого можна використовувати поряд зі стандартними типами, наприклад:
struct Worker < // опис нового типу Worker char f1o[30]; int date, code; double salary; >; // опис закінчується точкою з комою // визначення масиву типу Worker та покажчика на тип Worker: Worker staff[100], *ps;[/ccie_cpp]
Це дозволяє створювати зв'язкові списки структур.
Дляініціалізації структури значення її елементів перераховують у фігурних дужках у порядку їх опису:
struct < char fio [30]; int date, code; double salary; > worker = < "Страусенке". 31 . 215 . 3400.55 >;
При ініціалізації масивів структур слід укладати у фігурні дужки кожен елемент масиву (з огляду на те, що багатовимірний масив — це масив масивів):
struct complex < float real, im; > compl [2] [3] = < < < 1 . 1 >. < 1 . 1 >. < 1 . 1 >>. // Рядок 1. TO є масив compl[0] < < 2 . 2 >. < 2 . 2 >. < 2 . 2 >> // Рядок 2. тобто масив compl [1] & gt; ;
Доступ до полів структури виконується за допомогою операцій вибору. (точка) при зверненні до поля через ім'я структури та -> при зверненні через покажчик, наприклад:
Worker worker, staff [100], * ps; worker. fio = "Страусенке"; staff [8]. code = 215; ps - > salary = 0.12;
Якщо елементом структури є інша структура, то доступ до її елементів виконується через дві операції:
struct А < int а; double х; >; struct < А а; double х; >х [2]; х[0].а.а = 1; х [1]. х = 0.1;
Як видно з прикладу, поля різних структур можуть мати однакові імена, оскільки вони мають різну область видимості. Більше того, можна оголошувати в одній області видимості структуру та інший об'єкт (наприклад, змінну чи масив) з однаковими іменами, якщо при визначенні структурної змінної використовувати слово struct, але не раджу це робити – заплутати компілятор важче, ніж себе.
Бітові поля
struct Options < bool centerX: 1; bool centerY: 1; unsigned int shadow : 2; unsigned int palette : 4; > ;
Побутові поля можуть бути будь-якого цілого типу. Ім'я поля може бути відсутнім, такі поля служать для вирівнювання на апаратний кордон. Доступ до поля здійснюється звичайним способом - на ім'я. Адреса поля отримати не можна, проте в іншому бітові поля можна використовувати так само, як звичайні поля структури. Слід враховувати, що операції з окремими бітами реалізуються набагато менш ефективно, ніж з байтами та словами, тому що компілятор повинен генерувати спеціальні коди, та економія пам'яті підЗмінні обертається збільшенням обсягу коду програми. Розміщення бітових полів у пам'яті залежить від компілятора та апаратури.
Об'єднання (union)
Об'єднання застосовують для економії пам'яті у тих випадках, коли відомо, що більше одного поля одночасно не потрібно:
Об'єднання часто використовують як поле структури, при цьому в структуру зручно включити додаткове поле, що визначає, який елемент об'єднання використовується в кожен момент. Ім'я об'єднання можна не вказувати, що дозволяє звертатися до його полів безпосередньо:
Об'єднання застосовуються також різної інтерпретації однієї й тієї ж бітового уявлення (але, зазвичай, у разі краще використовувати явні операції перетворення типів). Як приклад розглянемо роботу зі структурою, що містить бітові поля:
struct Options < bool centerX: 1; bool centerY: 1; unsigned int shadow : 2; unsigned int palette : 4; > union < unsigned char ch; Options bit; > option = < 0xC4 >; cout
Порівняно із структурами на об'єднання накладаються деякі обмеження. Сенс деяких із них стане зрозумілим пізніше:
- об'єднання може ініціалізуватися лише значенням першого елемента;
- об'єднання неспроможна містити бітові поля;
- об'єднання не може містити віртуальні методи, конструктори, деструктори та операцію присвоєння;
- об'єднання не може входити до ієрархії класів.
За матеріалами книги Т.А. Павловській «C ++. Програмування мовою високого рівня».