Студопедия
Новини освіти і науки:
МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах


РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання


ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ"


ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ


Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків


Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні


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


Гендерна антидискримінаційна експертиза може зробити нас моральними рабами


ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ


ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів



Шаблони, шаблони-класи

У мові С++ можливе і параметричне програмування (програмування з використанням родових компонентів). Родові (параметризовані) компоненти мають властивість адаптуватися до конкретної ситуації, в якій такий компонент використовується. Це дозволяє розробляти достатньо універсальні, водночас високоефективні компоненти програм (зокрема, об’єкти).

Параметричне програмування у мові С++ реалізоване за допомогою шаблонів (template). У С++ визначено два види шаблонів: шаблони-класи та шаблони-функції.

Шаблони-класи можуть використовуватись різними способами, але найбільш очевидним є їх використання в якості адаптивних об’єктів пам’яті. Щоб навести найпростіший приклад, припустимо, що потрібно визначити об’єкти, які можуть зберігати по два значення, одне ціле, а інше символьне. Для цього ми могли б визначити

class pair … int … char {

public:

int first;

char second;

pair … int … char(int x, char y):first(x), second(y) {}

};

Після цього ми могли б написати, наприклад,

pair … int … char pair1(13,`a’);

cout<< pair1.first<< end1;

cout<< pair1.second<< end1;

Якщо, крім цього, нам потрібні об’єкти, які можуть зберігати, скажімо, бульове значення та число подвійної точності, ми могли б визначити

class pair … bool … double {

public:

bool first;

double second;

pair … bool … double(bool x, double y): first(x), second(y) {}

};

і написати, наприклад:

pair … bool … double pair1 (true, 0.1);

cout<< pair1.first<< end1;

cout<< pair1.second<< end1;

Те саме можна було б здійснити для нескінченного числа пар типів, але шаблон-клас дозволяє охопити всі ці випадки єдиним визначенням:

template <class T1, class T2>

class pair {

public:

T1 first;

T2 second;

pair (T1 x, T2 y):first (x), second (y) {}

};

Останнє визначення класу написане з використанням двох імен довільних типів Т1 та Т2, які є типами-параметрами. Ці імена вводяться визначенням типів-параметрів за допомогою конструкції template <class T1, class T2>, яка означає, що можна подавати фактичні імена типів замість Т1 та Т2, отримує контрастний екземпляр шаблона-класу pair. Наприклад, конструкції

pair <int, char> pair3 (13, ‘a’);

pair <bool, double> part4 (true, 0.1);

оголошують об’єкти pair3 та pair4, які структурно тотожні об’єктам pair1 та pair2 відповідно.

Але тепер можна використати pair у незчисленній множині інших випадків з іншими комбінаціями фактичних типів, як наприклад

pair <double, long > pair5 (3.1415, 999);

pair <bool, bool > pair6 (false, true);

Як фактичні типи можуть використовуватися типи, визначені через інші класи; наприклад

pair <pair … int … char, float > pair7 (pair1, 1.23);

чи, що еквівалентно,

pair <pair<int, char>, float > pair8(pair3, 1.23);

Як показано тут, можна використовувати типи, які одержані як примірники (представники) шаблонів-класів, всюди, де можна використовувати звичайні типи.

Визначення шаблона-класу pair є дуже простим прикладом параметричного контейнерного класу; проте його можна адаптувати до багатьох різних застосувань. Звичайне перетворення звичайного класу на параметризований (оскільки воно знаходить застосування в найширшому класі прикладних програм) більш корисне, ніж просто додавання ключового слова template та списку параметрів типів. Можуть бути корисними деякі модифікації, щоб бути впевненим у тім, що результуючі примірники об’єктів так само ефективні, як і об’єкти, визначені звичайним способом, незалежно від того, які типи фактично будуть підставлені. У разі, коли визначення шаблона-класу таке просте, як pair, то можна зробити поліпшення. Визначення шаблона-класу було дуже простим:

pair (T1 x, T2 y);

Проблема в тому, що х та у передаються за значенням. Це означає, що якщо ці об’єкти великі, то при виклику конструктора будуть робитися їх додаткові копії, а це дорого коштує. Щоб уникнути цього, потрібно передавати х та у як константні посилальні параметри, щоб передавалися лише адреси. Саме таким чином визначається pair в STL:

template <class T1, class T2>

class pair {

public:

T1 first;

T2 second;

pair (T1& x, T2& y):first (x), second (y) {}

};

При визначенні складніших класів, як правило, буде потрібно обчислити набагато більше параметрів, щоб забезпечити їх адаптованість та ефективність.

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

int intmax (int x, int y)

{

return x<y?y:x;

}

Вона може визначити максимальне тільки із двох цілих (int), але її легко узагальнити, перетворивши на шаблон-функцію:

template <class T>

T max(T x, T y)

{

return x < y ? y : x;

}

Основна відмінність шаблона-функції від шаблона-класу в тому, що не потрібно повідомляти компілятор, до яких типів параметрів застосовується функція, він сам може визначити це за типами її формальних параметрів.

int u = 3, v = 4;

double d = 4.7;

cout << max(u, v) << endl; //мається на увазі тип int

cout << max(d, 9.3) << endl; //мається на увазі тип double

cout << max(u, d) << endl; //помилка: невідповідність типів

Компілятор потребує, щоб через х та у передавалися значення однакових типів, оскільки в шаблоні для них було вказано один і той самий тип Т. Потрібно також, щоб було визначення операції < у вигляді списку її параметрів (Т, Т). Наприклад, повертаючись до використання шаблона-класу pair, визначеного в попередньому пунктi,

pair <double, long> pair 5(3.1415, 999);

компілятор видає помилку при компіляції оператора:

max (pair 5, pair 5);

через відсутність визначення операції operator < для об’єктів типу pair<double, long>. Але він буде компілювати, якщо попередньо ви­значити зміст операції operator < для об’єктів цього типу, наприклад:

pair <double, long> operator< (const pair <double, long)& x, const pair <double, long>& y)

//порівняти х та у за їх першими членами:

{

return x.first <y.first;

}

У цьому випадку компілятор може вияснити типи, які має на думці, та порівняти застосування операції чи виклик функції з правильними перевантаженими визначеннями, що робить шаблони-функ­ції найбільш зручним засобом параметричного програмування.

У висновку визначимо, що наведене визначення шаблона-функ­ції max може бути поліпшене так само, як це було зроблено для конструктора шаблона-класу pair, тобто введенням константних посилальних параметрів:

template <class T>

T max(const T& x, const T& y)

{

return x < y ? y : x;

}

Саме таке визначення використовується в STL.

Шаблони-функції як функції-члени

У визначенні звичайних класів чи шаблонів-класів функції-члени можуть мати шаблони в якості параметрів (у доповнення до шаблонів, які є параметрами класів). Ця нова властивість мови С++ використовується в шаблонах-класах при визначенні уміщуючих класів (контейнерів) STL. Наприклад, кожний уміщуючий клас має функцію-член insert, у якій є шаблон-параметр для визначення типу використовуваного ітератора:

template <class T>

сlass vector {

...

template <class Iterator >

insert(Iterator first, Iterator last);

...

};

Як буде показано далі, ця функція-член insert може використовуватися для того, щоб вставити елементи, які скопіювали з деякої іншої структури (наприклад, списку), використовуючи зв’язані з цією структурою ітератори. Визначення такої функції-члена як шаблона-функції, котрий має тип ітератора як параметра шаблона, робить її більш корисною, ніж коли б тип ітератора був у неї фіксований.

На жаль, надалі велика частина компіляторів С++ не підтримує функції-члени, які є шаблонами, що обмежує можливості STL.




Переглядів: 1850

<== попередня сторінка | наступна сторінка ==>
Реалізація залежностей | Параметри шаблонів, що опускаються

Не знайшли потрібну інформацію? Скористайтесь пошуком google:

  

© studopedia.com.ua При використанні або копіюванні матеріалів пряме посилання на сайт обов'язкове.


Генерація сторінки за: 0.012 сек.