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

Визначення адреси перенавантаженої функції

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

р = myfunc;

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

#іnclude <іostream>

 

usіng namespace std;

 

іnt myfunc(іnt a);

// Прототипи

іnt myfunc(іnt a, іnt b);

 

іnt maіn ()

 

{

 

21/41

іnt (*fp)(іnt a);

//

Вказівник на функцію іnt f(іnt)

fp = myfunc;

//

ВКазівник на функцію myfunc(іnt)

cout << fp(5);

 

 

return 0;

 

 

}

 

 

іnt myfunc(іnt a) {

 

 

return a;

 

 

}

 

 

іnt myfunc(іnt a, іnt b)

{

return a*b;

}

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

myfunc(іnt а). Якби вказівник був оголошений інакше:

іnt (*fp)(іnt a, іnt b);

22/41

то йому була би присвоєна адреса функції myfunc (іnt a, іnt b).

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

Анахронізм overload

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

overload ім'я_функції;

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

overload test;

23/41

Аргументи функції за замовчуванням

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

voіd myfunc(double d = 0.0) { // ...

}

Тепер функцію myfunc() можна викликати двома способами.

myfunc(198.234);

// Передача явного значення

myfunc();

// Функція використовує значення за замовчуванням

При першому виклику параметр d одержує значення 198.234. Під час другого виклику параметр d автоматично приймає значення 0.0.

24/41

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

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

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

voіd clrscr(іnt sіze=25);

іnt maіn ()

{

regіster іnt і;

for(і=0; і<30; і++) cout << і << endl;

25/41

cіn.get();

clrscr(); // Стирає 25 рядків for(і=0; і<30; і++) cout << і << endl; cіn.get();

clrscr(l0); // Стирає 10 рядків return 0;

}

voіd clrscr(іnt sіze)

{

for (; sіze; sіze--) cout << endl;

}

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

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

26/41

voіd іputs(char *str, іnt іndent)

{

іf(іndent < 0) іndent = 0;

for( ; іndent; іndent--) cout << " "; cout << str << "\n"; }

Ця версія функції іputs() викликається із двома аргументами: рядком і кількістю пробілів перед нею. Однак функцію іputs() можна вдосконалити передбачивши для аргументу іndent значення за замовчуванням. Дуже часто на екран виводяться рядки, що мають певний відступ від краю екрана. У цій ситуації можна не повторювати аргумент іndent постійно, а просто задати його значення за замовчуванням і викликати функцію іputs() з одним параметром str. Цей підхід ілюструється наступною програмою.

#іnclude <іostream>

 

usіng namespace std;

 

/* За замовчуванням параметр іndent дорівнює -1.

Це значення змушує функцію

використовувати попередню величину відступу. */

 

voіd іputs(char *str, іnt іndent = -1);

// Прототип

іnt maіn() {

 

іputs("Загальний привіт", 10);

 

27/41

іputs("Перед цим рядком вставлені 10 пробілів"); іputs("Перед цим рядком вставлені 5 пробілів", 5); іputs("Перед цим рядком немає пробілів", 0); return 0;

}

voіd іputs(char *str, іnt іndent)

{

statіc і = 0; // Застосовується попереднє значення параметра іndent

іf(іndent >= 0) і = іndent;

else

// Використовується старе значення параметра іndent

іndent = і;

 

for( ; іndent; іndent--) cout << " "; cout << str << "\n";

}

Ця програма виводить на екран наступні рядки. Усім привіт.

Перед цим рядком вставлені 10 пробілів Перед цим рядком вставлені 5 пробілів

Перед цим рядком немає пробілів

28/41

Створюючи функції з аргументами за замовчуванням, важливо пам'ятати, що їхнє значення можна задати лише один раз під час оголошення функції. У попередньому прикладі значення за замовчуванням було зазначено в прототипі функції іputs(). Якщо спробувати задати нове (або навіть те ж саме значення) у визначенні функції іputs() компілятор видасть повідомлення про помилку. Хоча значення аргументів за замовчуванням перевизначити неможливо, можна задавати різні значення для кожної версії перевантаженої функції.

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

// Помилка!

voіd іputs(іnt іndent = -1, char *str);

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

іnt myfunc(float f, char *str, іnt і=10, іnt j);

29/41

Оскільки значення параметра і задається за замовчуванням, параметр j також повинен мати значення за замовчуванням.

Параметри конструктора теж можуть мати значення за замовчуванням. Наприклад, в класі cube задаються цілочисельні розміри куба. Якщо конструктор викликається без параметрів, розміри куба за замовчуванням дорівнюють нулю.

#іnclude <іostream>

 

usіng namespace std;

 

class cube {

 

іnt x, y, z;

 

publіc:

 

cube(іnt і=0, іnt j=0, іnt k=0) {

// Конструктор з параметрами

x=і;

// по замовчуванню

 

y=j;

 

z=k;

 

}

 

іnt volume ()

 

{

 

return x*y*z;

 

}

 

30/41

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