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

Перевантаження функцій і операторів, спадкування в C++

Лекція № 2

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

Перевантаження операторів

Спадкування

Конструктори й деструктори

Приклади програм

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

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

сам процес називається перевантаженням функцій.

Щоб зрозуміти, наскільки важливий механізм перевантаження, розглянемо три функції, визначені в підмножині C: abs(), labs() і fabs(). Функція abs() повертає абсолютне значення цілого числа, функція labs() обчислює абсолютне значення змінної типу long int, а функція fabs() призначена для визначення абсолютного значення змінної типу double. Незважаючи на те що ці функції виконують практично ідентичні операції, у мові C для них передбачено три різних, хоча й мало відмінних імен. Це занадто ускладнює ситуацію, програміст повинен постійно пам'ятати, яку функцію варто викликати в тому чи іншому випадку. Однак у мові C++ всі три функції можна назвати однаково. Розглянемо приклад.

#include <iostream> using namespace std;

// Функція abs перевантажена тричі. int abs(int i);

2/33

double abs(double d);

 

long abs(long l);

 

 

int main()

 

 

{

<<

"\n";

cout << abs(-10)

cout << abs(-11.0)

<<

"\n";

cout << abs(-9L)

<<

"\n";

return 0; }

 

 

int abs (int i)

{ cout << "Функція abs() з аргументом типу int \n"; return i<0 ? -i : i;

}

double abs (double d)

{ cout << "Функція abs() з аргументом типу double\n"; return d<0.0 ? -d : d;

}

long abs(long l)

{ cout << "Функція abs() з аргументом типу long \n"; return l<0 ? -l : l;

}

3/33

Ця програма обчислює наступні результати.

Функція abs з аргументом типу int:

10

Функція abs з аргументом типу double: 11

Функція abs з аргументом типу long: 9

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

конкретну реалізацію залежно від контексту

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

4/33

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

тип і/або кількість параметрів кожної перевантаженої функції повинні бути різними.

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

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

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

5/33

Розглянемо ще один приклад перевантажених функцій.

#include <iostream> #include <cstdio> #include <cstring> using namespace std;

void stradd(char *sl, char *s2); void stradd(char *sl, int i); int main()

{

char str[80];

strcpy(str, "Всім "); stradd(str, "привіт"); cout << str << "\n";

stradd(str, 100); cout << str << "\n"; return 0; }

//Конкатенація двох рядків

void stradd(char *sl, char *s2)

{

strcat(sl, s2);

}

6/33

//Конкатенація рядка й цілого числа, перетвореного в рядок void stradd(char *sl, int i)

{

char temp[80];

sprintf(temp, "%d", i); // Передача змінної типу int в стрічку temp strcat(sl, temp);

}

Уцій програмі функція stradd() є перевантаженою. Одна її версія склеює два рядки (аналогічно функції strcat()). Інша версія спочатку перетворить ціле число в рядок, а потім конкатенує отримані рядки. Таким чином, завдяки перевантаженню можна створити єдиний інтерфейс, що дозволяє конкатенувати два рядки, а також рядок і ціле число.

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

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

7/33

2. Перевантаження операторів

Поліморфізм у мові C++ проявляється також у вигляді перевантаження операторів. Як відомо, для вводу й виводу в мові C++ застосовуються оператори ">>" і "<<". Це стало можливим завдяки тому, що в заголовному файлі <iostream> ці оператори перевантажені. Перевантажені оператори мають різний сенс для різних класів, зберігаючи при цьому своє первісне значення.

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

8/33

3. Спадкування

Як вказувалося раніше, спадкування є однієї з основних характерних рис об’єктно-орієнтованого програмування. У мові C++ спадкування виражається тим, що один клас може здобувати властивості іншогокласув момент свого оголошення.

Спадкування дозволяє створювати ієрархії класів, уточнюючи їхньої властивості від самих загальних до більше конкретних. Процес спадкування починається з визначення базового класу (base class), властивості якого будуть загальними для всіх його спадкоємців. Базовий клac являє собою опис найбільш загального характеру. Спадкоємці базового клacу називаються похідними класами (derived classes). Похідний клас має всі властивості базового класу й своїх специфічних особливостей.

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

Спочатку оголошується клас building. Він є основою для створення двох похідних класів.

9/33

class building

{

int rooms; int floors; int area;

public:

void set_rooms(int num); int get_rooms();

void set_floors(int num); int get_floors();

void set_area(int num); int get_area();

};

Для простоти всі будинки описуються лише трьома властивостями: кількістю кімнат, кількістю поверхів і загальною площею. Клас building включає ці компоненти у своєму оголошенні. Функції-члени, імена яких починаються із префікса set, задають значення закритих даних. Функції-члени, імена яких починаються із префікса get, витягають і повертають ці значення.

Тепер застосуємо це занадто загальний опис будинку для оголошення похідних класів, що описують більше конкретні види споруд. От як, наприклад, виглядає клас

house.

10/33

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