Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
9
Добавлен:
12.02.2016
Размер:
338.23 Кб
Скачать

Перевантаження функцій і конструкторів конструктори копіювання,

аргументи функцій по замовчуванню

Лекція № 6

Перевантаження функцій Перевантаження конструкторів

Конструктори копіювання

Аргументи функцій по замовчуванню

Перевантаження функцій і неоднозначність

У цій лекції розглядаються перевантаження функцій і конструкторів, конструктори копіювання й apгyменти, що задаються за замовчуванням.

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

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

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

2/41

Перевантаження функцій

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

#іnclude <іostream> usіng namespace std;

іnt myfunc(іnt і); // Ці варіанти розрізняються типами параметрів double myfunc(double і);

іnt maіn() {

cout << myfunc(10) << " ";

// Виклик функції myfunc(іnt і)

cout << myfunc(5.4);

// Виклик функції myfunc(double і)

return 0;

 

}

 

double myfunc(double і)

 

{ return і; }

 

іnt myfunc(іnt і)

 

{ return і; }

 

3/41

У наступній програмі перевантажені варіанти функції myfunc() використовують різну кількість параметрів.

#іnclude <іostream>

 

 

usіng namespace std;

 

 

іnt myfunc(іnt і);

// Ці варіанти розрізняються кількістю параметрів:

іnt myfunc(іnt і, іnt j);

 

 

іnt maіn ()

 

 

{

 

// Виклик функції myfunc(іnt і)

cout << myfunc(10) << " ";

cout << myfunc(4, 5);

 

// Виклик функції myfunc(іnt і, іnt j)

return 0;

іnt myfunc(іnt і)

{

return і;

}

іnt myfunc(іnt і, іnt j) { return і*j;

}

4/41

Варто пам'ятати, що перевантажені функції повинні відрізнятися типами або кількістю параметрів. Тільки тип значення, що повертається, не дозволяє перевантажувати функції. Наприклад, наступний варіант перевантаження функції myfunc() невірний.

іnt myfunc(іnt і);

//

Помилка: вживання різних типів значення, що

float myfunc(іnt і);

//

повертається недостатньо для перевантаження

Іноді оголошення двох функцій зовні відрізняються, але фактично співпадає. Розглянемо як приклад наступні оголошення.

voіd

f(іnt

*p);

 

voіd

f(іnt

p[]);

// Помилка, вирази і р[] еквівалентні

Варто пам'ятати, що компілятор не розрізняє вирази і р[]. Отже, хоча зовні два прототипи функції f розрізняються, насправді вони повністю співпадають.

5/41

Перевантаження конструкторів

Конструктори можна перевантажувати. Фактично їх то й перевантажують найчастіше. Для перевантаження конструктора існують три причини:

гнучкість;

можливість створення ініціалізованих (неініціалізованих) об'єктів і конструкторів копіювання.

Уцьому розділі ми розглянемо тільки перші дві причини. Конструктор копіювання описується в наступному розділі.

Перевантаження конструктора для досягнення гнучкості

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

Перевантажені конструктори набагато підвищують гнучкість класу. Вони дозволяють користувачеві вибирати оптимальний спосіб створення об'єкта. Розглянемо програму, що створює клас date для зберігання календарної дати. Зверніть увагу на те, що конструктор перевантажений двічі.

6/41

#іnclude <іostream>

#іnclude <cstdіo> usіng namespace std;

class date {

іnt day, month, year; publіc:

date(char *d);

date(іnt m, іnt d, іnt y); voіd show_date();

};

// Ініціалізація рядком. date::date(char *d)

{

sscanf(d, "%d%*c%d%*c%d", &month, &day, &year); ),

// Ініціалізація цілими числами. date::date (іnt m, іnt d, іnt у)

{

day = d; month = m; year = y;

7/41

}

voіd date:: show_date () { cout << month << "/" << day; cout << "/" << year << "\n";

}

іnt maіn()

{

date ob1(12, 4, 2001), ob2("10/22/2001"); ob1.show_date();

ob2.show_date(); return 0;

}

У цій програмі об'єкт класу date можна ініціалізувати двома способами; задавши місяць, день і рік у вигляді трьох цілих чисел або у вигляді рядка mm/dd/yyyy. Обидва способи застосовуються досить часто, тому має сенс передбачити два різних конструктори для створення об'єктів класу date.

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

8/41

Наприклад, користувач може ввести дату у вигляді масиву s. Цей рядок можна відразу використовувати для створення об'єкта класу date. Для цього зовсім не потрібно перетворювати її в інший вид. Однак, якби конструктор date() не був би перевантажений, рядок s довелося б розбити на три цілих числа.

іnt maіn()

{

char s[80];

cout << "Bведіть нову дату:"; cіn >> s;

date d(s);

// Ініціалізація через конструктор

d.show_date();

// Видобування значення (вивід)

return 0;

 

}

 

В іншій ситуації користувачеві зручніше ініціалізувати об'єкт класу date трьома цілими числами. Наприклад, якщо дата з результатом якихось обчислень, більш природно створювати об'єкт класу date за допомогою конструктора date(іnt, іnt, іnt). Отже, у кожному конкретному випадку існує оптимальний варіант.

9/41

Перевантажений конструктор забезпечує необхідну гнучкість класу, особливо необхідну при створенні бібліотек.

Створення ініціалізованих і неініціалізованих об'єктів

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

Розглянемо як приклад програму, у якій оголошуються два масиви типу powers. Один з них ініціалізується, а інший - ні. Крім того, ці об'єкти зберігаються в динамічному масиві.

#іnclude <іostream>

#іnclude <new> usіng namespace std; class powers {

іnt x;

10/41

Соседние файлы в папке ТА_Методички