Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
8
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

8.3.3. Особливості використання аргументів, що передаються функції за замовчуванням

Хоча передача аргументів функції за замовчуванням, є дуже могутнім засобом програмування (за умови їх коректного використання), з ними можуть іноді виникати проблеми. Їх призначення дає змогу функції ефективно виконувати свою роботу, забезпечуючи при всій простоті цього механізму значну гнучкість. У цьому сенсі всі передані аргументи функції за замовчуванням повинні відображати спосіб найбільш загального використання функції або альтернативного її застосування. Якщо не існує деякого єдиного значення, яке звичайно присвоюється тому або іншому параметру, то і немає сенсу оголошувати відповідний аргумент за замовчуванням. Насправді оголошення аргументів, що передаються функції за замовчуванням, при недостатній для цього підставі деструктуризує програмний код, оскільки такі аргументи здатні збити з пантелику будь-кого, кому доведеться розбиратися в такій програмі. Нарешті, основним принципом використання аргументів за замовчуванням повинен бути, як у лікарів, принцип "не нашкодити". Іншими словами, випадкове використання аргументу функції за замовчуванням не повинно призвести до незворотних негативних наслідків. Адже такий аргумент можна просто забути вказати під час виклику деякої функції, і, якщо це трапиться, то подібний промах не повинен викликати, наприклад, втрату важливих даних!

8.4. Перевантаження функцій і неоднозначності, що при цьому виникають

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

Неоднозначності виникають тоді, коли компілятор не може визначити відмінність між двома перевантаженими функціями.

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

int myFunc(double d);

. . .

cout << myFunc('с'); // Помилки немає, виконується перетворення типів

Як зазначено в коментарі, помилки тут немає, оскільки мова C++ автоматично перетворить символ 'c' в його double-еквівалент. Взагалі кажучи, у мові програмування C++ заборонено достатньо мало видів перетворень типів. Незважаючи на те, що автоматичне перетворення типів – це дуже зручно, воно, проте, є головною причиною неоднозначності. Розглянемо таку програму.

Код програми 8.13. Демонстрація неоднозначності внаслідок перевантаження функцій

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

float myFunc(float izm);

double myFunc(double izm);

int main()

{

// Неоднозначності немає, викликається функція myFunc(double)

cout << myFunc(10.1) << " ";

// Виникнення неоднозначності.

cout << myFunc(10);

getch(); return 0;

}

float myFunc(float izm)

{

return izm;

}

double myFunc(double izm)

{

return -izm;

}

У цій програмі завдяки перевантаженню функція myFunc() може приймати аргументи або типу float, або типу double. У процесі виконання рядка коду програми

cout << myFunc(10.1) << " ";

не виникає ніякої неоднозначності: компілятор мови C++ "впевнено" забезпечує виклик функції myFunc(double), оскільки, якщо не задано безпосередньо інше, всі літерали з плинною крапкою у мові програмування C++ автоматично отримують тип double. Але під час виклику функції myFunc() з аргументом, що дорівнює цілому числу 10, у програму вноситься неоднозначність, оскільки компіляторові невідомо, в який тип йому необхідно перетворити цей аргумент: float або double. Обидва перетворення є допустимими. У такій неоднозначній ситуації буде видано повідомлення про помилку, і програма не скомпілюється. На прикладі попередньої програми хотілося б наголосити, що неоднозначність в ній викликана не перевантаженням функції myFunc(), оголошеної двічі для прийому double- і float-аргументу, а використанням при конкретному виклику функції myFunc() аргументу невизначеного для перетворення типу. Іншими словами, помилка полягає не в перевантаженні функції myFunc(), а в конкретному її виклику.

А ось ще один приклад неоднозначності, викликаної автоматичним перетворенням типів у мові програмування C++.

Код програми 8.14. Демонстрація помилки, спричиненої неоднозначністю

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

char myFunc(unsigned char ch);

char myFunc(char ch);

int main()

{

cout << myFunc('с'|); // Тут викликається myFunc(char).

cout << myFunc(88) << " "; // Вноситься неоднозначність.

getch(); return 0;

}

char myFunc(unsigned char ch)

{

return ch-1;

}

char myFunc(char ch)

{

return ch+1;

}

У мові програмування C++ типи unsigned char і char не є істотно неоднозначними, позаяк це різні типи. Але під час виклику функції myFunc() з цілочисельним аргументом 88 компілятор "не знає", яку функцію йому виконати, тобто в значення якого типу йому необхідно перетворити число 88: типу char або типу unsigned char? Обидва перетворення тут цілком допускаються.

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

Код програми 8.15. Демонстрація ще одного прикладу неоднозначності

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

int myFunc(int izm);

int myFunc(int izm, int jzm=1);

int main()

{

cout << myFunc(4, 5) << " "; // Неоднозначності немає

cout << myFunc(10); // Виникнення неоднозначності

getch(); return 0;

}

int myFunc(int izm)

{

return izm;

}

int myFunc(int izm, int jzm)

{

return izm*jzm;

}

У цій програмі в першому зверненні до функції myFunc() задається два аргументи, тому у компілятора немає ніяких сумнівів у виборі потрібної функції, а саме myFunc(int izm, int jzm), тобто ніякої неоднозначності у цьому випадку не виникає. Але під час другого звернення до функції myFunc() ми отримуємо неоднозначність, оскільки компілятор "не знає", чи то йому викликати версію функції myFunc(), яка приймає один аргумент, чи то використовувати можливість передачі аргументу функції за замовчуванням до версії, яка приймає два аргументи.

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

Розділ 9. С++-специфікатори та спеціальні оператори

Перш ніж переходити до перегляду складніших засобів мови програмування C++, є сенс грунтовніше познайомитися з С++-специфікаторами типів даних і класів пам'яті, а також з деякими спеціальними операторами. Окрім вже розглянутих вище типів даних, y мові програмування C++ визначено ще й інші. Одні з них складаються з модифікаторів, що додаються до вже відомих типів, інші містять перерахунки, а треті використовують ключове слово typedef. Мова C++ також підтримує ряд операторів, які значно розширюють область дії мови і дають змогу розв'язувати задачі програмування у надзвичайно широкому діапазоні. Йдеться про порозрядні оператори, оператори зсуву, а також оператори "?" і sizeof. Окрім того, у цьому розділі розглядаються такі спеціальні оператори, як new і delete. Вони призначені для підтримки С++-системи динамічного розподілу пам'яті.