- •1 Парадигми та мови програмування
- •1.1 Процедурне програмування
- •1.2 Об'єктне (модульне) програмування
- •1.3 Об'єктно-орієнтовне програмування
- •2 Програмне середовище
- •3 Базові поняття програмування
- •4 Процедурно-орієнтоване програмування
- •4.1 Функції
- •4.2 Вбудовані (inline) функції
- •4.3 Передача параметрів
- •4.4 Обчислення значення функцій
- •4.4. Обчислення значення функції — вихід із функції; особливості повернення та використання іменованого значення, іменованої константи
- •4.5 Рекурсія
- •4.5. Рекурсія
- •4.6 Довизначення (overloading) функцій
- •4.6. Довизначення (overloading) функцій
- •4.7 Узагальнені функції (function template)
- •4.8 Непряме використання функцій: указники на функції, їх тип, ініціалізація і присвоєння
- •4.9 Видимість
- •4.10 Тривалість життя об’єктів
- •5 Об'єктне програмування
- •5.1 Класи і об'єкти, члени класів
- •5.2 Інтерфейс класу, реалізація класу; визначення і оголошення класу
- •5.3 Створення і ініціалізація об'єктів, довизначення конструкторів, замовчуваний конструктор, копіювання, поверхневе і глибоке копіювання, ініціалізація і присвоєння, копіювальний конструктор
- •5.4 Cтатичні члени класів і статичні класні функції
- •5.5 Константні об'єкти, константні функції, змінювані члени константних об'єктів (mutable)
- •5.6 Поточний об'єкт this, указники на члени класу і класні функції, порівняння з указниками на (позакласні) функції, указники на статичні члени класу
4.5 Рекурсія
4.5. Рекурсія
Функції можуть викликатися рекурсивно
int gcd (int v1, int v2)
{
return v2 ? gcd (v2, v1%v2): v1;
}
Рекурсію часто легше записати, ніж ітерацію, але вона може виявитись досить неефективною. Якщо, не думаючи, переписати визначення чисел Фібоначчі в рекурсивну функцію, час обчислень може стати експоненціальним
int BadFib(int n)
{
// Так не варто рахувати!!!
switch (n)
{
case 0:
return 0; break;
case 1:
return 1; break;
default:
return BadFib(n-1)+BadFib(n-2);
}
}
Але це не проблема рекурсії, а проблема неефективної схеми обчислень. Дійсно, підраховуючи n-1-е число Фібоначчі корисно пам’ятати обчислене перед цим n-2-е:
void fib(int &f1, int &f2, int n)
{
int f;
if (n>=2)
{
f=f2; f2+=f1; f1=f;
fib(f1, f2, n-1);
}
}
int Fibonacci (int n)
{
int f0=0, f1=1;
switch (n)
{
case 0:
return f0;break;
case 1:
return f1; break;
default:
fib(f0, f1, n);
return f1;
}
}
4.6 Довизначення (overloading) функцій
4.6. Довизначення (overloading) функцій
Візьмемо дві функції
void DisplayInt( int intParam )
{
cout << "The integer is: " << intParam << "\n";
}
void DisplayString( char *text )
{
cout << "The text is: " << text << "\n";
}
що мають одне й те ж призначення: вивести значення свого аргументу. Але правила типізації вимагають двох різних визначень залежно від типу параметру. Правда, два різних визначення не вимагають двох різних імен функцій. Ми вже давно звикли до вживання одного і того ж символу для позначення, наприклад, операції додавання чисел, векторів, матриць, інтегралів і ще чого завгодно. Так само функції з наведеного прикладу ми можемо позначити спільним іменем
void Display( int intParam )
{
cout << "The integer is: " << intParam << "\n";
}
void Display( char *text )
{
cout << "The text is: " << text << "\n";
}
Їх виклик
Display(a)
буде розпізнаватися за типом параметру. Ясно, що для використання цих функцій нам потрібні будуть обидва прототипи
void Display( int );
void Display( char * );
При необхідності список функцій з одним і тим же іменем може бути розширений шляхом довизначення (overloading) цієї функції для іншого типу параметрів, наприклад,
void Display( double );
Можна визначити декілька функцій для обчислення максимуму
int max (int x, int y) { return x>y? x: y; }
double max (double x, double y) { return x>y? x: y; }
int max (int x, int y, int z) { return max(x, max(y,z));}
Особливо популярним є довизначення стандартних операцій. Наприклад, визначимо структуру точки площини
struct Point{ double x; double y;}
Point operator+(Point u, Point v)
{
Point w;
w.x = u.x + v.x;
w.y = u.y + v.y;
return w;
}
Можна уявити собі декілька сигнатур додавання:
Point operator+(Point, Point);
Point operator+(Point &, Point &);
Point operator+(const Point &, const Point &);
Подумайте, на якому з них зупинитися.
Можна також довизначити порівняння точок на рівність
bool operator==(Point u, Point v)
{
return (u.x == v.x) && (u.y == v.y);
}
нерівність і багато чого іншого.
Наявність багатьох визначень для однієї й тієї ж операції вимагає від компілятора деяких додаткових зусиль для пошуку варіанту, підходящого до кожного конкретного виклику. Певну проблему в цьому пошуку створює можливість неявного зведення типів, наприклад, у виклику Display (’a’).