- •7. Робота з шаблонними, функціями та класами
- •7.1. Поняття про узагальнені функції
- •7.1.1. Механізм реалізації шаблонної функції з одним узагальненим типом
- •7.1.2. Безпосередньо задане перевизначення узагальненої функції
- •7.1.3. Шаблонна функція з двома узагальненими типами
- •7.1.4. Механізм перевизначення специфікації шаблону функції
- •7.1.5. Використання стандартних параметрів у шаблонних функціях
- •7.2. Поняття про узагальнені класи
- •7.1.6. Обмеження, які застосовуються при використанні узагальнених функцій
- •7.1.7. Приклад створення узагальненої функції abs()
- •7.2.1. Створення класу з одним узагальненим типом даних
- •7.2.2. Створення класу з двома узагальненими типами даних
- •7.2.3. Приклад створення узагальненого класу для організації безпечного масиву
- •7.2.4. Використання в узагальнених класах аргументів, що не є узагальненими типами
- •11.2.1. Передача покажчиком на функцію її адреси іншій функції
- •9.2.3. Класи потоків
- •9.3. Особливості механізмів перевизначення операторів введення-виведення даних
- •9.3.1. Створення перевизначених операторів виведення даних
- •9.5. Організація файлового введення-виведення даних
- •9.5.1. Відкриття та закриття файлу
- •9.5.2. Зчитування та запис текстових файлів
- •9.5.3. Неформатне введення-виведення даних у двійковому режимі
- •9.5.4. Зчитування та записування у файл блоків даних
- •10. Динамічна ідентифікація типів і оператори приведення типу
- •10.1. Динамічна ідентифікація типів
- •10.1.1. Отримання типу об'єкта у процесі виконання програми
- •10.1.2. Приклад rtti-застосування
- •11. Поняття про простори імен та інші ефективні програмні засоби
- •11.1. Особливості організації простору імен
- •11.1.1. Поняття про простори імен
- •11.1.2. Застосування настанови using
- •11.1.3. Неіменовані простори імен
- •11.1.4. Застосування простору імен std
- •11.2. Застосування покажчиків на функції
- •11.2.2. Пошук адреси перевизначеної функції
- •11.3. Поняття про статичні члени-даних класу
- •11.5. Застосування до функцій-членів класу модифікаторів const і mutable
- •11.6. Використання explicit-конструкторів
- •12. Введення в стандартну бібліотеку шаблонів
- •12.1. Огляд стандартної бібліотеки шаблонів
- •12.2. Поняття про контейнерні класи
- •12.3. Механізми роботи з векторами
- •12.3.1. Доступ до елементів вектора за допомогою ітератора
- •12.3.2. Вставлення та видалення елементів з вектора
- •12.3.3. Збереження у векторі об'єктів класу
- •12.3.4. Доцільність використання ітераторів
- •7. Робота з шаблонними, функціями та класами 1
- •7.1. Поняття про узагальнені функції 1
- •10. Динамічна ідентифікація типів і оператори приведення типу 26
- •11. Поняття про простори імен та інші ефективні програмні засоби 31
- •12. Введення в стандартну бібліотеку шаблонів 44
11.1.3. Неіменовані простори імен
Існує неіменований простір імен спеціального типу, який дає змогу створювати ідентифікатори, унікальні для цього файлу. Загальний формат його оголошення має такий вигляд:
namespace {
// Оголошення
}
Неіменовані простори імен дають змогу встановлювати унікальні ідентифікатори, які відомі тільки в області видимості одного файлу. Іншими словами, члени файлу, який містить неіменований простір імен, можна використовувати безпосередньо, без уточнюючого префікса. Але поза файлом ці ідентифікатори є невідомими.
Як уже зазначалося вище у цьому навчальному посібнику, використання модифікатора типу static також дає змогу обмежити область видимості глобального
простору імен файлом, у якому він оголошений. Наприклад, розглянемо такі два файли, які є частиною однієї і тієї ж самої програми:
-
Файл One
Файл Two
static int f;
void Fun1() {
f = 99; //OK
}
extern int f;
void Fun2() {
f = 10; // Помилка
}
Оскільки змінну f визначено у файлі One, то її і можна використовувати у файлі One. У файлі Two змінну f визначено як зовнішню (extern-змінна), а це означає, що її ім'я і тип відомі, але саму змінну f насправді не визначено. Коли ці два файли будуть скомпоновані, спроба використовувати змінну f у файлі Two призведе до виникнення помилки, оскільки у ньому немає визначення для змінної f. Той факт, що f оголошена як static-змінна у файлі One, означає, що її область видимості обмежується цим файлом, і тому вона недоступна для файлу Two.
Незважаючи на те, що використання глобальних static-оголошень все ще дозволено стандартом мови програмування C++, проте для локалізації ідентифікатора у межах одного файлу краще використовувати неіменований простір імен. Розглянемо такий приклад:
-
Файл One
Файл Two
namespace {
int f;
}
static int f;
void Fun1() {
f = 99; // OK
}
extern int f;
void Fun2() {
f = 10; // Помилка
}
Тут змінну f також обмежено рамками файлу One. Для нових програм рекомендується використовувати замість модифікатора static неіменований простір імен.
Зазвичай для більшості коротких програм і програм середнього розміру немає потреби у створенні просторів імен. Але, формуючи бібліотеки багаторазово використовуваних функцій або класів, є сенс помістити свій програмний код (якщо хочете забезпечити його максимальну переносність) у власний простір імен.
11.1.4. Застосування простору імен std
Стандарт мови програмування C++ визначає всю свою бібліотеку у власному просторі імен, який іменується std. Саме з цієї причини більшість програм у цьому навчальному посібнику містять таку настанову:
using namespace std; // Використання стандартного простору імен
У процесі виконання цієї настанови простір імен std стає поточним, що відкриває прямий доступ до імен функцій і класів, визначених у цій бібліотеці, тобто під час звернення до них відпадає необхідність у використанні префікса std::.
Звичайно, при бажанні можна безпосередньо кваліфікувати кожне бібліотечне ім'я префіксом std::. Наприклад, наведений нижче код програми не привносить бібліотеку в глобальний простір імен.
Демонстрація механізму використання безпосередньо заданої кваліфікації бібліотечних імен префіксом std::
#include <iostream> // Для потокового введення-виведення
int main()
{
double n;
std::cout << "Введіть число: "; std::cin >> n;
std::cout << "Ви ввели число ";
std::cout << n;
getch(); return 0;
}
У цьому коді програми імена cout і cin безпосередньо доповнені іменами своїх просторів імен. Отже, щоб записати дані у стандартний вихідний потік, необхідно використовувати не просто ім'я потоку cout, а ім'я з префіксом std::cout, а щоб зчитати дані із стандартного вхідного потоку, потрібно застосувати "префіксне" ім'я std::cin.
Якщо Ваша програма використовує стандартну бібліотеку тільки в обмежених межах, то, можливо, її і не варто вносити в глобальний простір імен. Але, якщо Ваша програма містить сотні посилань на бібліотечні імена, то набагато простіше зробити простір імен std поточним, ніж повністю кваліфікувати кожне ім'я окремо.
Якщо Ви використовуєте тільки декілька імен із стандартної бібліотеки, то, ймовірно, є сенс використовувати настанову using для кожного з них окремо. Перевага цього підходу полягає у тому, що ці імена можна, як і раніше, використовувати без префікса std::, не вносячи при цьому всю бібліотеку стандартних функцій у глобальний простір імен. Розглянемо такий приклад.
Демонстрація механізму внесення в глобальний простір імен декількох імен
#include <iostream> // Для потокового введення-виведення
// Отримуємо доступ до імен потоків cout і cin
using std::cout;
using std::cin;
int main()
{
double n;
cout << "Введіть число: "; cin >> n;
cout << "Ви ввели число ";
cout << n;
getch(); return 0;
}
У цьому коді програми імена потоків cin і cout можна використовувати безпосередньо, але інша частина простору імен std не внесена в область видимості.
Як уже зазначалося вище, початкова бібліотека мови програмування C++ була визначена в глобальному просторі імен. Якщо Вам доведеться модернізувати старі С++-програми, то програміст повинен або включити в них настанову usingnamespace std, або доповнити кожне звернення до члена бібліотеки префіксом std::.
Це особливо важливо, якщо Вам доведеться замінювати старі заголовні *.h-файли сучасними заголовками
