4.9. Програмен обхват
По рано беше
отбелязано, че всеки идентификатор в програмата трябва да бъде уникален. Това не
означава, обаче, че едно име може да бъде използувано само веднъж в програмата.
Името може да бъде използувано повторно при условие, че съществува някакъв
контекст, според който да бъдат разграничавани различните представители. Един
такъв контекст е сигнатура на функция. В последния раздел, например, putValues()
се използува като име на две функции. Всяка от тях има уникална разграничителна
сигнатура.
Един втори, по-общ контекст е обхвата. С++ поддържа три вида
обхват: файлов, локален и класов. Файловият обхват се отнася за тази част от
текста на програмата, който не се съдържа във функция или дефиниция на клас. Той
представлява най-външният обхват на програмата. Може да се каже, че той обхваща
както локалния, така и класовия обхват.
Най-общо, локалният обхват се
свързва с тази част от текста на програмата, която се съдържа в дефницията на
функцията. Счита се, че всяка функция има ясно дефиниран локален обхват. В
тялото на функцията за всеки съставен оператор (или блок), съдържащ един или
повече декларативни оператори, се поддържа определен локален обхват. Локалният
обхват на даден блок може да бъде вложен. Списъкът от аргументи се разглежда
като принадлежащ на локалния обхват на функцията. Не може да се каже, че
списъкът от аргументи принадлежи на файловият обхват.
Раздел 6.8
представя подробно обсъждане на класовият обхват. Съществуват две важни бележки,
които ще направим сега:
1. Счита се, че всеки клас представя ясно
разграничен класов обхват.
2. Членовете - функции се разглеждат като включени
в обхвата на класа.
От езика се гарантира, че всяка глобална променлива,
която не е инициализирана явно получава стойност 0. По такъв начин при следните
две дефиниции променливите i и j получават начална стойност 0
int i =
0;
int j;
Стойността на една неинициализирана локална променлива не е
дефинирана.
Дадено име може да бъде използувано повторно когато е налице
разлика в обхвата. Например, в следния програмен фрагмент има четири уникални
представители на ia
void swap( int *ia, int, int);
void sort( int *ia,
int sz );
void putValues( int *ia, int sz );
int ia[] = { 4, 7, 0, 9,
2, 5, 8, 3, 6, 1 };
const SZ = 10;
main() {
int i, j;// ...
swap(
ia, i, j );
sort( ia, SZ );
putValues( ia, SZ );
}
С всяка
променлива се свързва някакъв обхват, който заедно с името й я идентифицира
уникално. Променливата и видима за програмата само в рамките на обхвата си
(иначе казано в областта си на действие). Една локална променлива, например, е
достъпна само във функцията, където е дефинирана – това е причината, поради
която името й може да бъде използувано повторно в рамките на друг обхват без да
възникне конфликт.
Променлива, дефинирана в рамките на файлов обхват, е
видима в цялата програма. Има три случая, при които видимостта й се
потиска:
1. Една локална променлива може да използува име на глобална
променлива. Тогава се казва, че глобалната променлива е скрита от локалния
представител. Как програмистът може да получи достъп до скритата глобална
променлива? Едно решение предлага оператора за обхват (scope
-оператор).
2. Нека една променлива е дефинирана в даден файл, но се
използува също и в друг или множество други файлове. Как програмистът декларира
променливата в тези файлове? Едно решение предлага ключовата дума
extern.
3. Нека две глобални променливи са дефинирани в различни
програмни файлове и имат еднакви имена, но възнамеряваме да ги използуваме като
различими обекти. Всяка от тях сама по себе си се компилира нормално. Когато ги
компилираме заедно, обаче, се отбелязва, че са дефинирани неколкократно и се
прекъсва процеса на компилация. Как програмистът може да компилира програмата
без да му се налага да променя всички представители на една от променливите?
Използуването на ключовата дума stаtic предлага едно решение. Тези три случая са
обект на обсъждане в следващите три раздела.
Оператор за обхват
(scope)
Операторът за обхват предлага едно решение на проблема за
достъп до скрита глобална променлива. Идентификатор, предшествуван от оператор
за обхват, ще ви осигури достъп до глобален представител. В следващия пример,
проектиран да илюстрира как може да бъде използуван оператора за обхват, една
функция изчислява числата на Фибоначи. В нея са зададени две дефиниции на
променливата max. Глобалният представител на променливата съдържа максималната
стойност за числата от поредицата. Локалният й представител показва желаната
дължина на редицата. (Да припомним, че формалните аргументи на една функция се
включват в локалния й обхват). Двата представителя на max трябва да бъдат
достъпни във функцията. Всяко явно обръщение към max, обаче, ще бъде отнесено
към локалния представител. За да имаме достъп до глобалния представител трябва
да използуваме оператора за обхват - max. Ето една реализация
#include
<stream.h>
const max = 65000;
const lineLength = 12;
void
fibonacci( int max ) {
if (max < 2 ) return; cout << "0 1 ";
for
( int i = 3, v1 = 0, v2 = 1, cur; i << max; ++i) {
cur = v1 +
v2;
if ( cur > max ) break;
cout << cur << " ";
v1 =
v2;
v2 = cur;
if ( i % lineLenggth == 0 ) cout << "n";
}
}
Ето и една реализация на main(), отнасяща се до примерната
функция
#include <stream.h>
void fibonacci( int );
main()
{
cout << "Fibonacci Series 16n";
fibonacci( 16 );
return
0;
}
Когато компилираме и изпълним тази програма ще получим следния
резултат
Fibonacci Series
16 0 1 1 2 3 5 8 13 21 34 55 89 144 233 337
610