Еквівалентність типів

При обробці операції присвоювання вигляду

х=вираз

компілятор мови програмування або дозволить, або не дозволить її виконання, якщо типи лівої та правої частин не збігаються (це залежить від компілятора конкретної мови програмування). У випадку різнотипних лівої та правої частин можливі неадекватний результат, втрата значимості тощо. Тому перевірка еквівалентності типів логічна в багатьох випадках. Існує два типи еквівалентності: структурна та іменна.

При використанні структурної еквівалентності два об'єкти належать еквівалентним типам, якщо їх структури однакові. Тому компілятор дозволяє присвоювання в операторі square=kut/2, оскільки структурно ці дві змінні належать типу float. Фактично при структурній еквівалентності похідні типи – не більше ніж синоніми для імені породжувального.

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

Успадкування атрибутів

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

Розглянемо просту програму для обчислення площі прямокутника:

#include <stdio.h>

Main()

{

typedef float length, square;

length x,y;

square a;

scanf("%d%d',&x,&y);

a=x*y;

printf("a=%d',a);

}

Якщо операція * успадковується від типу float,то розумно припустити, що тип результату операції х*у такий самий, як і тип операндів (у нашому випадку – тип length). Отже, операція присвоювання а=х*у; незаконна, тому що змінна a типу square. Операція присвоювання х=х*у; є законною, але нісенітницею з погляду предметної галузі.

Однак мова С++ має механізми перевизначення існуючих операцій і визначення нових. Операція *, визначена для двох операндів типу type1, відрізняється від операції *, визначеної для двох операндів типу type2. У таких випадках говорять, що операція перевантажена. Яка операція мається на увазі в конкретному контексті, визначається компілятором при дослідженні типів передбачуваного результату. Тому використання а=х*у; цілком коректне.

Перераховні типи

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

enum day_of_week{mon, tue, wed, the, fri, sat, son};

Кожне значення типу позначається ім'ям ідентифікатора, за допомогою якого на це значення потім посилаються. Значення відповідних ідентифікаторів за умовчанням у мові С визначаються як послідовні цілі числа, починаючи з 0. Такий порядок можна змінити, присвоївши відповідному ідентифікатору необхідне число. Наприклад, можемо досить елегантно визначити новий тип для зображення шістнад­цяткового числа:

Enum hexx

{A=10,B,C,D,E,F};

Десяткові цифри 0–9 будуть одночасно й шістнадцятковими, тому немає необхідності в їх перевизначенні. Тут усі символи від 'А' до 'F' перевантажені. Оскільки порядкові значення нового типу безпосередньо зображують фактичні шістнадцяткові, то програмування істотно спрощується.

Логічні типи

Логічний тип позначає логічні значення true чи false, необхідні у програмуванні. Його конкретна реалізація здійснюється у різних мовах по-різному. Наприклад, у Pascal він описується за допомогою ключового слова boolean. У деяких С -подібних мовах істинним вважається будь-яке значення, відмінне від нульового, а хибним – нульове (що належить до цілого типу). У новому стандарті С++ є тип bool.

Перелічимо стандартні логічні операції, що зазвичай застосовуються до операндів логічного типу, даючи в результаті логічне значення:

a логічне доповнення;

a логічне "і";

a логічне "або";

a логічне виключне "або".

Операції порівняння <, >, <>, <=, >=, == завжди повертають логічні значення, наприклад, 3 < 5 повертає значення істина. Операції відношення перевантажені в тому розумінні, що вони можуть застосовуватися до даних різних типів, зокрема до цілих чи дійсних операндів. Операція порівняння ==, застосована до даних логічного типу, реалізує функцію логічної еквівалентності, а операція <> відіграє роль операції виключного "або".

Основне призначення логічного типу полягає в реалізації умов для умовного оператора та операторів циклу. Однак про це далі.

Символьні типи

Більшість мов програмування містять визначений символьний тип char. Об'єкти типу char можуть містити одне символьне значення, що зображується на машинному рівні цілим в області від 0 до 255 ([–128, 127]). Фактичне зображення кожного символу залежить від набору символів (напр., ASCIІ), що використовується.

У таблиці ASCII -кодів порядковий номер кожного символу відповідає коду ASCII для цього символу.

Числові типи

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

Зображення цих двох різних типів чисел на обчислювальній машині породжує деякі проблеми, більшість з яких пов'язані з вимогою машинної незалежності й мобільності. Цілі числа можуть бути точно зображеними на обчислювальній машині, але тільки в скінченній області; дійсні ж числа не завжди допускають точне зображення.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: