Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Відповіді на питання по мові С++по лекціям.docx
Скачиваний:
2
Добавлен:
01.05.2025
Размер:
265.22 Кб
Скачать
  1. Перевантаження функції.

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

Головним у перевантаженні функцій є список аргументів, який ще називають сигнатурою функції. Коли дві функції використовують однакові по кількості аргументів та однакові типу і вони слідують у тому ж порядку, то функції мають одну й ту ж сигнатуру. Імена змінних не мають значення. С++ має можливість визначити дві функції з одним ім’ям при умові, що ці функції мають різні сигнатури. Сигнатури можуть розрізнятися по кількості аргументів або по їх типу, або по тому або іншому.

Перевантаження доцільне використовувати для функцій, котрі виконують одні й тій самій дії, але з різними типами даних. Крім того, має сенс оцінити можливість досягнення тієї ж цілі за допомогою аргументів, які приймаються за замовчуванням. Наприклад, можна змініть єдину функцію left(), яка використовується для обробки рядків двома перевантаженими функціями:

char * left(const char * str, unsigned n); //два аргументи

char * left(const char * str); //один аргумент

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

Головним у перевантаженні функцій є список аргументів, який ще називають сигнатурою функції. Коли дві функції використовують однакові по кількості аргументів та однакові типу і вони слідують у тому ж порядку, то функції мають одну й ту саму сигнатуру. Імена змінних не мають значення. С++ має можливість визначити дві функції з одним ім’ям при умові, що ці функції мають різні сигнатури. Сигнатури можуть розрізнятися по кількості аргументів або по їх типу, або по тому або іншому.

Перевантаження доцільне використовувати для функцій, котрі виконують одні й ті ж дії, але з різними типами даних. Крім того, має сенс оцінити можливість досягнення тієї ж цілі за допомогою аргументів, які приймаються за замовчуванням. Наприклад, можна змініть єдину функцію left(), яка використовується для обробки рядків двома перевантаженими функціями:

char * left(const char * str, unsigned n); //два аргументи

char * left(const char * str); //один аргумент

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

  1. Шаблони функцій.

Шаблони – це узагальнення опису функцій. Передаючи шаблону тип в якості параметру, то можна змусити компілятор згенерувати функцію для цього типу даних, такий як int або double. Оскільки шаблони дозволяють програмувати на основі узагальненого типу замість визначеного типу даних, то цей процес має назву узагальненого програмування. Оскільки типи представлені параметрами, то шаблони функцій іноді називають параметрізованими типами.

Коли треба застосувати функції глобального пошуку і заміни, наприклад, слова int словом double, можна рядки

int x;

short interval;

перетворити таким чином:

double x; //намір змінити тип

short doubleerval; //не має намір змінити ім’я змінної

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

template <class Any>

void Swap (Any &a, Any &b)

{

Any temp;

temp = a;

a = b;

b = temp;

}

Перший рядок вказує, що встановлюється шаблон, і довільному типу даних присвоюється ім’я Any. В опис обов’язково входять ключові слова template і class (замість class можна використовувати ключове слово typename), а також кутові дужки. Ім’я типу вибирається довільним (у нашому прикладі – Any), при цьому треба дотримувати звичайні правила іменування мови С++. Багато програмістів застосовують прості імена, наприклад, Т. Остання частина програмного коду описує алгоритм обміну значеннями типу Any. Шаблони не створюють ні яких функцій. Компілятор створює функцію відповідно образку шаблону, підставляючи int замість Any. Аналогічно цьому, для створення функції, що здійснює обмін значеннями типу double, компілятор використовуючи вимоги шаблона, підставляє тип double замість Any.

У С++ з’явилося нове ключове слово typename, яке можна використовувати замість ключового слова class у нашьому контексті. Це визначає, що визначення шаблона можна записати у такій формі:

template < typename Any>

void Swap (Any &a, Any &b)

{

Any temp;

temp = a;

a = b;

b = temp;

}

Ключове слово typename підкреслює, що параметр Any є тип. У той же час створені бібліотеки програмних кодів,котрі розроблені з застосуванням ключового слова class. Стандарт С++ розглядає обидва ключових слова як ідентичні.

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

  1. Перевантажені шаблони.

Шаблони використовуються тоді, коли потрібно створити функції, котрі застосовують один і той же алгоритм до різних типів даних. Однако, один і той же алгоритм може бути застосований не для всіх типів даних. Для таких випадків можна застосувати перевантаження шаблонів, аналогічно перевантаженню звичайних функцій. Наприклад, вхідний шаблон має сигнатуру (Any &, Any &), у той час як новий шаблон має сигнатуру (Any [], Any [], int)

Зверніть увагу, що останній аргумент є визначений тип (int), а не узагальнений. Не усі аргументи шаблонів обов’язково повинні мати узагальнений тип.

Коли у наступній програмі компілятор зустрічає перший виклик функції swap(), він знаходить, що в неї два аргументи типу int, і порівнює її з вхідним шаблоном. Однак, до другого випадку використовуються функція, де в якості аргументів виступають два масиви елементів типу int і значення типу int, що відповідає новому шаблону.

ЛЕКЦІЯ 27.

  1. Явні спеціалізації.

Приклад визначення структури:

Struct job

{

char name[40];

double salary;

int floor;

};

Оскільки, С++ дозволяє присвоювати одну структуру іншій, цей код працює адже у тому випадку, коли тип Any є структурою job. Але ми хочемо зробити тільки обмін між елементами salary і floor, а елементи name оставити без змін. Для цього потрібно іншій програмний код, але аргументи функції swap () зістаються як у першому випадку (посилання на дві структури job), так що неможливо застосувати перевантажений шаблон, щоб застосувати альтернативний код.

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

У новому стандарті С++ прийняти наступні положення:

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

  • Прототип і визначення явної спеціалізації повинно починатися з позначення trmplate <>, а також вказувати ім’я звичайного типу даних.

  • Спеціалізація перекриває звичайний шаблон, а звичайна функція перекриває і спеціалізацію, і шаблон.

  1. Приведемо приклади прототипів усіх трьох форм функцій.

Приклади прототипів усіх трьох форм функцій, які здійснюють обмін даними для структур типу job.

//прототип звичайної функції

void swap (job &, job &);

 //прототип шаблона

template <class Any>

void swap (job &, job &);

 //явна спеціалізація для типу job

template <> void swap < job > (job &, job &);

Для компіляції прототип звичайної функції має пріоритет перед явною спеціалізацією і шаблоном. Явна спеціалізація має пріоритет перед шаблоном. В наступному прикладі коду перший виклик є зверненням до явної спеціалізації, що основана на типі job:

template <class Any>

void swap (job &, job &);

//явна спеціалізація для типу job

template <> void swap < job > (job &, job &);

int main () {

double u, v; …

Swap (u, v); //використати шаблон

int a, b; …

Swap (a, b); //використати void swap < job > (job &, job &)

}

  1. Створення екземплярів і спеціалізації.

Коли компілятор використовує шаблон для створення визначення функції для визначеного типу даних, то результат має назву створення екземпляра шаблона. Наприклад, у розглянутої програмі виклик функції Swap (i, j) вимагає компілятор генерувати екземпляр Swap (), використовуючи тип даних int. Об’ява функції є не шаблон, а визначений екземпляр шаблону, що використовує тип даних int. Такий спосіб створення екземплярів шаблонів отримав назву неявне створення екземплярів, оскільки компілятор робить висновок про необхідність побудови визначення, виявляючи, що у програмі використовується функція Swap () з параметрами типу int.

  1. Явне створення екземплярів.

Це визначає можливість дати компілятору пряму команду створити визначений екземпляр, наприклад, Swap <int> (). Синтаксис потребує вказати використовуваний тип даних за допомогою визначення < >, а також почати об’яву з ключового слова template:

template void swap <int> (int, int); //явне створення екземпляру

Компілятор, в якому реалізована ця властивість, виївши таку об’яву. використовує шаблон функції Swap (), щоб згенерувати екземпляр функції, що застосовує тип int.

  1. Порівняємо явне створення екземплярів з явною спеціалізацією.

Порівняємо явне створення екземплярів з явною спеціалізацією, яка використовує одне із наступних еквівалентних об’яв:

template <> swap <int> (int &, int &); //явна спеціалізація

template <> swap (int &, int &); //явна спеціалізація

Різниця між цими об’явами визначає наступне: “не використовувати шаблон функції Swap (), щоб генерувати визначення функції; замість цього використати окреме, спеціалізоване визначення функції, яке явно сформульоване для типу int”. Ці прототипи повинні бути асоційовані з їх власними визначеннями функцій. В об’яві явної спеціалізації створення екземпляра цього визначення опускається.

Неявне і явне створення екземплярів, а також явна спеціалізація отримали загальну назву – спеціалізація. Загальним для них є те, що вони визначають об’яву функції, в основу якої покладені визначення типу даних, а не визначення функції, яка є узагальненим описом.

Коли компілятор знаходить явне створення екземпляра для типу char, він використовує визначення шаблону, щоб генерувати версію функції Swap (), яка призначена для даних типу char. В інших випадках виклик функції Swap () компілятор відносить шаблон з використанням для виклику аргументів. Наприклад, коли компілятор знаходить функції Swap (a, b), він генерує версію цьому типу. Коли компілятор знаходить функції Swap (n, m), він застосовує окреме визначення (явна спеціалізація), створення для типу даних job. Коли ж компілятор знаходить функції Swap (g, h), він приймає спеціалізацію шаблона, згенерованого раніш, коли компілятор виконував явне створення екземпляра. Правила пошуку найбільш спеціалізованого шаблону називають правилами окремого упорядкування шаблонів функції.

ЛЕКЦІЯ 28.