Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лекції 2012-2013ооп.docx
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
6.61 Mб
Скачать

Лекція № 5

Тема 5. Функції програмування С++

План лекції

1.Користувацькі типи - typedef, enum, struct, union; функції.

2.Передача параметрів таповернення значень з функцій.

3.Рекурсія, перевантаження функцій, функція main з параметрами.

4.Глобальні і локальні визначення, простори імен та їх використання.

5.Директиви препроцесора.

6.Стандартний ввід/вивід - бібліотека stdio.h.

7.Основи потокового введенню/виводу - бібліотека iostream.h.

Зміст лекції

Програми на мові C++ зазвичай створюються шляхом компонування одного або декількох об'єктних файлів (файлів .obj) з однією або декількома бібліотеками. Бібліотекою називається колекція компонованих файлів, які або поставляються разом з компілятором, або отримуються окремо, або створюються і компілюються самим програмістом. Усі компілятори C++ поставляються з бібліотекою функцій (чи процедур) і класів, які можна включити в програму. Функція - це програмний блок, який виконує деякі службові дії, наприклад складає два числа або виводить інформацію на екран. Клас можна розглядати як колекцію цих і пов'язаних з ними функцій.

Функція за своєю суттю - це підпрограма, яка може маніпулювати даними і повертати деяке значення. Кожна програма C++ має принаймні одну функцію main(), яка при запуску програми викликається автоматично. Функція main() може викликати інші функції, ті, у свою чергу, можуть викликати наступні і так далі

5.1. Користувацькі типи - typedef, enum, struct, union. Функції.

Оголошення і визначення функцій

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

Оголошення функції

Існує три способи оголошення функції.

- Запишіть прототип функції у файл, а потім використовуйте вираження з #include, щоб включити його у свою програму.

- Запишіть прототип функції у файл, в якому ця функція використовується.

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

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

По-перше, вимога розташовувати функції у файлі в певному порядку утрудняє підтримку програми в процесі зміни умов її використання.

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

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

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

Приклади прототипів функцій :

long FindArea(long length, long width); // повертає значення типу long, має два параметри

void PrintMessage(int messageNumber); // повертає значення типу void, має один параметр

int GetChoice(); // повертає значення типу int, не має параметрів

BadFunction(); // повертає значення типу int, не має параметрів

Приклади визначень функцій :

long FindArea(long l, iong w)

{

return 1 * w;

}

void PrintMessage(int whichMsg)

{

if (whichMsg == 0)

cout << "Hello.\n";

if (whichMsg == 1)

cout << "Goodbye.\n";

if (whlchMsg > 1)

cout << "I' m confused.\n";

}

Виконання функцій

При виклику функції її виконання починається з вираження, яке коштує першим після відкриваючої фігурної дужки ({). У тілі функції можна реалізувати галуження, використовуючи умовний оператор if (і деякі інші оператори, які розглядаються на занятті 7). Функції можуть також викликати інші функції і навіть самих себе (про рекурсію мова піде нижче в цій главі).

Локальні змінні

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

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

Лістинг 5.2. Використання локальних змінних u параметрів функції

1: #include <iostream.h>

2:

3: float Convert(float);

4: int main()

5: {

6: float TempFer;

7: float TempCel;

8:

9: cout << "Please enter the temperature in Fahrenheit : ";

10: cin >> TempFer;

11: TempCel = Convert(TempFer);

12: cout << "\nHere's the temperature in Celsius: ";

13: cout << TempCel << endl;

14: return 0;

15: }

16:

17: float Convert(float TempFer)

18: {

19: float TempCel;

20: TempCel = ((TempFer - 32) * 5) / 9;

21: return TempCel;

22: }

Результат:

Please enter the temperature in Fahrenheit : 212

Here's the temperature in Celsius : 100

Please enter the temperature in Fahrenheit : 32

Here's the temperature in Celsius : 0

Please enter the temperature in Fahrenheit : 85

Here's the temperature in Celsius : 25.4444

Аналіз: В рядках 6 і 7 оголошуються дві змінні типу float : одна (TempFer) для зберігання значення температури в градусах за Фаренгейтом, а інша (TempCel) - в градусах за Цельсієм. У рядку 9 користувачеві пропонується ввести температуру за Фаренгейтом, і це значення потім передається функції Convert().

Після виклику функції Convert() програма продовжує виконання з першого вираження в тілі цієї функції, представленого рядком 19, де оголошується локальна змінна, також названа TempCel. Зверніть увагу, що ця локальна змінна - не та ж сама змінна TempCel, яка оголошена в рядку 7. Ця змінна існує тільки усередині функції Convert(). Значення, передане як параметр TempFer, також є лише переданим з функції main() локальною копією однойменної змінної.

У функції Convert() можна було б задати параметр FerTemp і локальну змінну CelTemp, що не вплинуло б на роботу програми. Щоб переконатися в цьому, можете ввести нові імена і перекомпілювати програму.

Локальній змінній TempCel привласнюється значення, яке виходить в результаті виконання наступних дій, : віднімання числа 32 з параметра TempFer, множення цієї різниці на число 5 з наступним діленням на число 9. Результат обчислень потім повертається як значення повернення функції, і в рядку 11 воно привласнюється змінній TempCel функції main(). В рядку 13 це значення виводиться на екран.

У нашому прикладі програма запускалася тричі. Вперше вводиться значення 212, щоб переконатися в тому, що точка кипіння води за Фаренгейтом (212) згенерує правильну відповідь в градусах Цельсія (100). При другому випробуванні вводиться значення точки замерзання води. Утретє - випадкове число, вибране для отримання дробового результату.

Ключове слово typedef

Іноді стомливо і нудно багаторазово повторювати запис таких ключових слів, як unsigned short int. (Крім того, в цих трьох словах нехитро наробити ще і купу помилок.) У мові C++ передбачена можливість створення псевдоніма для цієї фрази шляхом використання ключового слова typedef, яке означає визначення типу.

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

typedef unsigned short int USHORT;

створюється нове ім'я USHORT, яке можна використовувати скрізь, де треба визначити змінну типу unsigned short int. Лістинг 3.3 перероблений з лістингу 3.2 з використанням псевдоніма USHORT замість слів unsigned short int.

Лістинг 3.3. Приклад визначення типу за допомогою typedef

1: // * * * * * * * * * * * * * * * * *

2: // Приклад визначення типу за допомогою typedef

3: #include <iostream.h>

4:

5: typedef unsigned short int USHORT; //визначення псевдоніма

6:

7: int main()

8: {

9: USHORT Width = 5;

10: USHORT Length;

11: Length = 10;

12: USHORT Area = Width * Length;

13: cout << "Width:" << Width << "\n";

14: cout << "Length: " << Length << endl;

15: cout << "Area: " << Area << endl;

16: return 0;

17: }

Результат:

Width: 5

Length: 10

Area: 50

У рядку 5 ідентифікатор USHORT за допомогою ключового слова typedef визначений як псевдонім типу unsigned short int. У іншому ця програма аналогічна попередній, представленій в лістингу 3.2, та і результати роботи обох програм співпадають.

У яких випадках слід використовувати типи short і long

Початкуючим програмістам часто буває важко прийняти рішення про те, коли оголошувати змінну з використанням типу long, а коли - з використанням типу short. Правило досить просте: якщо існує хоч щонайменший шанс, що ваше значення буде занадто великим для передбачуваного типу, використовуйте тип з великим розміром.

Змінні типу unsigned short int, як правило, мають розмір, рівний двом байтам, і можуть зберігати значення, що не перевищує 65 535. Знакові короткі цілі ділять свій діапазон між позитивними і негативними числами, тому їх максимальне значення удвічі менше, ніж у беззнакового короткого цілого.

Хоча змінні типу unsigned long int можуть зберігати дуже велике число (4 294 967 295), воно все-таки кінцеве. Якщо вам треба працювати з ще більшими числами, доведеться перейти до використання типів float або double, але при цьому ви декілька програєте в точності. Змінні типу float і double можуть зберігати надзвичайно великі числа, але на більшості комп'ютерів значущими залишаються тільки перші 7 або 19 цифр, тобто після вказаної кількості цифр число округляється.

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

Для створення перерахування використовується ключове слово enum, за яким йдуть: ім'я типу, відкриваюча фігурна дужка, список константних значень, розділених комами, закриваюча фігурна дужка і крапка з комою. Наприклад:

enum COLOR { RED, BLUE, GREEN, WHITE, BLACK };

Цей вираз виконує два завдання.

1. Створюється перерахування з ім'ям C0L0R, що є новим типом.

2. Визначаються символьні константи: RED зі значенням 0; BLUE зі значенням 1; GREEN зі значенням 2 і так далі

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

enum Color { RED=100, BLUE, GREEN=500, WHITE, BLACK=700 };

те константа red матиме значення 100; константа blue - 101; константа GREEN - 500; константа WHITE - 501; константа BLACK - 700.

Тепер можна визначити змінні типу C0L0R, але кожною з них можна присвоїти тільки одне зі значень (в даному випадку RED, BLUE, GREEN, WHITE або BLACK або 100, 101, 500, 501 або 700), що перераховують. Змінній C0L0R можна присвоїти будь-яке значення кольору. Насправді цій змінній можна присвоїти будь-яке ціле значення, навіть якщо воно не відповідає жодному з дозволених кольорів, але в цьому випадку пристойний компілятор повинен обуритися і показати застережливе повідомлення. Важливо розуміти, що змінні перерахування насправді мають тип unsigned int і цілочисельним змінним привласнюються задані константи перерахування. Проте іноді при роботі з кольорами, днями тижня або іншими подібними наборами значень непогано мати можливість називати ці значення по імені. У лістингу 3.7 представлена програма, в якій використовується тип перерахування.

Лістинг 3.7. Використання перерахування

1: #include <iostream.h>

2: int main()

3: {

4: enum Days { Sunday, Monday, Tuesday

5: Wednesday, Thursday, Friday, Saturday };

6: int choice;

7: cout << "Enter a day (0-6) : ";

8: cin << choice;

9: if (choice = Sunday || choice == Saturday)

10: cout << "\nYou're already off on weekends!\n";

11: else

12: cout << "\nOkay, I'll put in the vacation day.\n";

13: return 0;

14: }

Результат:

Enter a day (0-6) : 6

You're already off on weekends!

Аналіз: В рядку 4 визначається перерахування DAYS з сім'ю константними значеннями. Усі вони утворюють зростаючу послідовність чисел, починаючи з нуля; таким чином, значення вівторка (Tuesday) дорівнює 2.

Користувачеві пропонується ввести значення між 0 і 6. Він не може ввести слово Sunday, оскільки в програмі не передбачений переклад символів в значення перерахування. Але можна перевірити введене користувачем значення, порівнявши його з константними значеннями перерахування, як показано в рядку 9. Використання перерахування полегшує аналіз програми. Того ж ефекту можна добитися, використовуючи константи цілочисельного типу, як показано в лістингу 3.8.

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

Лістинг 3.8. Та ж програма, але з використанням констант цілочисельного типу

1: #include <iostream.h>

2: int main()

3: {

4: const int Sunday = 0;

5: const int Monday = 1;

6: const int Tuesday = 2;

7: const int Wednesday = 3;

8: const int Thursday = 4;

9: const int Friday = 5;

10: const int Saturday = 6: 11;

12: int choice;

13: cout << "Enter a day (0-6) : ";

14: cin << choice;

15:

16: if (choice = Sunday || choice == Saturday)

17: cout << "\nYou're already off on weekends!\n";

18: else

19: cout << "\nOkay, I'll put in the vacation day.\n";

20:

21: return 0;

22: }

Результат:

Enter a day (0-6) : 6

You're already off on weekends!

Результати роботи цієї програми ідентичні результатам програми з лістингу 3.7. Але в цьому варіанті усі константи (Sunday, Monday і ін.) визначені в явному виді і відсутній тип перерахування Days. Зверніть увагу, що програма з перерахуванням коротша і логічніша.

Структури

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

Спробуємо повторно ввести вміст лістингу 6.8 з урахуванням наступних змін:

- в рядку 3 замінимо оголошення class Point оголошенням struct Point;

- в рядку 17 замінимо оголошення class Rectangle оголошенням struct Rectangle.

Тепер знову запустимо нашу програму і порівняємо результати. При цьому ніякої різниці ви помітити не повинні.

Чому два ключові слова несуть однакове смислове навантаження

Ви, ймовірно, здивовані тим, що два різні ключові слова створюють практично ідентичні оголошення. Так склалося історично. Мова C++ будувалася як розширення С. В мові З були структури, але ці структури не мали методів класу. Творець C++, Бьерн Страуструп, спирався на структури, але замінив ім'я типу даних struct типом class, щоб тим самим заявити про нові розширені функціональні можливості цієї нової освіти.

Рекомендуется:Используйте специфікатор const скрізь, де це можливо. Переконаєтеся, що вам повністю зрозумілі класи, перш ніж переходити до наступного заняття.

Поміщайте оголошення класу у файл з розширенням .hpp, а його виконання - у файл з розширенням .cpp.

Ключові слова C++

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

auto, break, case, catch, char, class, const, continue, default, delete, do, double, else, enum, extern, float, for, friend, goto, if, int, long, mutable, new, operator, private, protected, public, register, return, short, signed, sizeof, static, struct, switch, template, this, throw, typedef, union, unsigned, virtual, void, volatile, while