Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Не підтверджено.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
3.08 Mб
Скачать

Namespace ns { int d;

}

У цьому записі простір імен NS розділено на дві частини. Проте вміст кожної частини належить до одного і того ж простору імен NS.

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

  1. Застосування настанови using

Якщо програма містить багато посилань на члени певного простору імен, то неважко уявити, що потреба вказувати ім'я цього простору імен при кожному зве­рненні до них, дуже скоро набридне Вам. Цю проблему дає змогу вирішити наста­нова using, яка застосовується у таких двох форматах: using namespace ім'я, using пате::чпен;

Настанова using робить заданий простір імен "видимим", тобто ді­ючим.

У першій формі елемент ім'я задає назву простору імен, до якого Ви зможете отримати доступ. Всі члени, визначені усередині заданого простору імен, потрап­ляють в "поле видимості", тобто стають частиною поточного простору імен і їх можна потім використовувати без кваліфікації (уточнення простору імен). У дру­гий формі робиться "видимим" тільки вказаний член простору імен. Наприклад, вважаючи, що простір імен CounterNameSpace визначено (як це показано вище), то наступні настанови using і присвоєння будуть цілком законними:

using CounterNameSpace::lowerbound; // Видимим став тільки член lowerbound. lowerbound = 10; // Все гаразд, оскільки член lowerbound знаходиться в області видимості.

using namespace CounterNameSpace; // Всі члени видимі, upperbound = 100; // Все гаразд, оскільки всі члени видимі.

Використання настанови using продемонстровано у наведеному нижче коді програми (яка є новим варіантом лічильника з попереднього розділу).

Код програми 11.2. Демонстрація механізму використання настанови using для виконання розрахунку у зворотному порядку

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

namespace CounterNameSpace {

int upperbound; int lowerbound;

class counter { int count; public:

counter(int n) {

if(n <= upperbound) count = n; else count = upperbound;

}

void Reset(int n) {

if(n <= upperbound) count = n;

}

int RunO {

if(count > lowerbound) return count--; else return lowerbound;

}

};

}

int mainO

{

// Використовується тільки член upperbound з // простору імен CounterNameSpace. using CounterNameSpace::upperbound;

//Тепер для встановлення значення змінній upperbound // не потрібно вказувати простір імен, upperbound = 100;

// Але під час звернення до змінної lowerbound і до інших // об'єктів, як і раніше, необхідно вказувати простір імен. CounterNameSpace::lowerbound = 0;

CounterNameSpace::counter ObjA (10); int c;

cout«"Розрахунок у зворотному порядку для об'єкта ObjA"« endl; do {

с = ObjA.RunO; cout« c «"";

} while(c > CounterNameSpace::lowerbound); cout« endl;

//Тепер використовуємо весь простір імен CounterNameSpace. using namespace CounterNameSpace;

counter 0bjß(20);

cout«"Розрахунок у зворотному порядку для об'єкта ObjB"« endl; do {

с = ObjB.RunO; cout« c «"";

}while(c> lowerbound); cout« endl;

ObjB.Reset(IOO); lowerbound = 80;

cout«"Розрахунок у зворотному порядку для об'єкта ObjB"« endl; do {

с = ObjB.RunO;

cout« с «"

} while(c > lowerbound); cout« endl;

getchO; return 0;

}

Ця програма ілюструє ще один важливий момент: якщо певний простір імен стає "видимим", то це означає, що він просто додає свої імена до імен інших, вже діючих просторів. Тому до кінця цієї програми до глобального простору імен до­далися і std, і CounterNameSpace.

  1. Неіменовані простори імен

Існує неіменований простір імен спеціального типу, який дає змогу створюва­ти ідентифікатори, унікальні для цього файлу. Загальний формат його оголошення має такий вигляд:

namespace {

// Оголошення

}

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

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

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

файли, які є частиною однієї і тієї ж самої програми:

Файл One

Файл Two

static int f;

extern int f;

void Fun10 {

voidFun2(){

II

CO

CO

о

f = 10; //Помилка

}

}

Оскільки змінну f визначено у файлі One, то її і можна використовувати у файлі One. У файлі Two змінну f визначено як зовнішню (extern-змінна), а це озна­чає, що її ім'я і тип відомі, але саму змінну f насправді не визначено. Коли ці два файли будуть скомпоновані, спроба використовувати змінну f у файлі Two призве­де до виникнення помилки, оскільки у ньому немає визначення для змінної f. Той факт, що f оголошена як static-змінна у файлі One, означає, що її область видимості обмежується цим файлом, і тому вона недоступна для файлу Two.

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

Файл One

Файл Two

namespace { intf;

}

static int f; void Fun10 { f = 99;// OK

}

extern int f;

voidFun2(){

f = 10; //Помилка

}


Тут змінну f також обмежено рамками файлу One. Для нових програм реко­мендується використовувати замість модифікатора static неіменований простір імен.

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

  1. Застосування простору імен std

Стандарт мови програмування C++ визначає всю свою бібліотеку у власному просторі імен, який іменується std. Саме з цієї причини більшість програм у цьому навчальному посібнику містять таку настанову:

using namespace std; // Використання стандартного простору імен У процесі виконання цієї настанови простір імен std стає поточним, що від­криває прямий доступ до імен функцій і класів, визначених у цій бібліотеці, тобто під час звернення до них відпадає необхідність у використанні префікса std::.

Простір імен std використовується власною бібліотекою мови програ­мування C++.

Звичайно, при бажанні можна безпосередньо кваліфікувати кожне бібліотеч­не ім'я префіксом std::. Наприклад, наведений нижче код програми не привносить бібліотеку в глобальний простір імен.

Код програми 11.3. Демонстрація механізму використання безпосередньо заданої кваліфікації бібліотечних імен префіксом std::

#include <iostream> // Для потокового введення-виведення

int mainO

{

double n;

std::cout«"Введіть число:"; std::cin » n;

std::cout«"Ви ввели число";

std::cout« п; getchO; return 0;

}

У цьому коді програми імена cout і сіп безпосередньо доповнені іменами сво­їх просторів імен. Отже, щоб записати дані у стандартний вихідний потік, необ­хідно використовувати не просто ім'я потоку cout, а ім'я з префіксом std::cout, а щоб зчитати дані із стандартного вхідного потоку, потрібно застосувати "префік- сне" ім'я std::cin.

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

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

Код програми 11.4. Демонстрація механізму внесення в глобальний простір імен декількох імен

#include <iostream> // Для потокового введення-виведення

// Отримуємо доступ до імен потоків cout і сіп

using std::cout;

using std::cin;

int mainO

{

double n;

cout«"Введіть число:сіп » n;

cout«"Ви ввели число cout« п; getchO; return 0;

}

У цьому коді програми імена потоків сіп і cout можна використовувати безпо­середньо, але інша частина простору імен std не внесена в область видимості.

Як уже зазначалося вище, початкова бібліотека мови програмування C++ бу­ла визначена в глобальному просторі імен. Якщо Вам доведеться модернізувати старі С++-програми, то програміст повинен або включити в них настанову using namespace std, або доповнити кожне звернення до члена бібліотеки префіксом std::. Це особливо важливо, якщо Вам доведеться замінювати старі заголовні Мі-файли сучасними заголовками.

Нео! хідноапам ятати! Старі заголовні *.1і-файли поміщають свій вміст у глобальний простір імен, а сучасні заголовки - у простір імен Std.

  1. Застосування покажчиків на функції

Покажчик на функцію - це достатньо складний, але дуже потужний засіб С++-програмування. Незважаючи на те, що функція не є змінною, проте вона за­ймає фізичну область пам'яті, певну адресу якої можна присвоїти покажчику. Ад­реса, що присвоюється покажчику, є вхідною точкою функції1. Якщо деякий по­кажчик посилається на функцію, то її (функцію) можна викликати за допомогою цього покажчика.

Покажчик на функцію посилається на вхідну точку цієї, функції.

Покажчики на функції також дають змогу передавати функції як аргументи іншим функціям. Адресу функції можна отримати, використовуючи ім'я функції без круглих дужок і аргументів2. Якщо присвоїти адресу функції покажчику, то цю функцію можна викликати через покажчик. Щоб зрозуміти сказане, розгляне­мо наведену нижче програму. Вона містить дві функції - vLineO і hLineO, які малю­ють на екрані вертикальні та горизонтальні лінії заданої довжини.

Код програми 11.5. Демонстрація механізму застосування покажчиків на функції

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

void vLine(int і), hLine(int і);

int mainO

{

void (*p)(int і);

p = vLine; // Покажчик на функцію vLine()

(*p)(4); //Виклик функції vLineO

p = hLine; // Покажчик на функцію hLine()

(*p)(5); // Виклик функції hLine() getchO; return 0;

}

void hLine(int і)

{

for(; і; і--) cout« cout« endl;

}

void vLine(int і)

{

for(; і; і--) cout«"|" « endl;

}

Ось ж виглядають результати виконання цієї програми:

Розглянемо цю програму у деталях. У першому рядку тіла функції mainO виз­начається змінна р як покажчик на функцію, яка приймає один цілочисельний ар­гумент і не повертає ніякого значення. Це оголошення не визначає, про яку саме функцію йдеться. Воно тільки створює покажчик, який можна використовувати для адресації будь-якої функції цього типу. Необхідність круглих дужок, у які по­міщено покажчик *р, випливає з С++-правил передування.

У наступному рядку покажчику р присвоюється адреса функції vLineO- Потім здійснюється виклик функції vLine() з аргументом 4. Після цього покажчику р при­своюється адреса функції hLine(), і за допомогою цього покажчика реалізується її виклик. У цьому коді програми під час виклику функцій за допомогою покажчика використовується такий формат:

(*р)(4);

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

р(4);

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

  1. Передача покажчиком на функцію її адреси іншій функції

Незважаючи на те, що у наведеному вище прикладі покажчик на функцію ви­користано тільки заради ілюстрації, часто таке його застосування має дуже важли­ве значення. Покажчик на функцію дає змогу передавати її адресу іншій функції. Як показовий приклад можна навести функцію qsortO із стандартної С++-бібліоте- ки. Функція qsortO - це функція швидкого сортування, що базується на алгоритмі Quicksort, який упорядковує вміст масиву. Її прототип має такий вигляд:

void qsort(void *start, size_t length size_t size,

int (*compare) (const void *, const void *));

Прототип функції qsortO "прописаний" у заголовку <cstdlib>, у якому також визначено тип size_t (як тип unsigned int). Щоб використовувати функцію qsortO, не~ обхідно передати їй покажчик на початок масиву об'єктів, який Ви хочете відсор­тувати (параметр start), довжину цього масиву (параметр length), розмір у байтах кожного елемента (параметр size) і покажчик на функцію порівняння елементів масиву (параметр * compare).

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

Щоби зрозуміти, як можна використовувати функцію qsortO, розглянемо на­ведену нижче програму.

Код програми 11.6. Демонстрація механізму використання бібліотечної функції qsort() для сортування елементів текстового масиву

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

#include <cstdlifc» // Для використання бібліотечних функцій

#include <cstring> // Для роботи з рядковими типами даних

using namespace std; // Використання стандартного простору імен