Область видимости объектов
Область видимости (scope) представляет часть программы, в пределах которой можно использовать объект. Как правило, область видимости ограничивается блоком кода, который заключается в фигурные скобки В зависимости от области видимости создаваемые объекты могут быть глобальными, локальными или автоматическими.
Глобальные объекты
Глобальные переменные определены в файле программы вне любой из функций и могут использоваться любой функцией.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
void print();
int n = 5;
int main()
{
print(); // n=6
n++;
std::cout << "n=" << n << std::endl; // n=7
return 0;
}
void print()
{
n++;
std::cout << "n=" << n << std::endl;
}
Здесь переменная n является глобальной и доступна из любой функции. При этом любая функция может изменить ее значение.
Локальные объекты
Объекты, которые создаются внутри блока кода (он может представлять функцию или какую-либо конструкцию типа циклов), называются локальными. Такие объекты доступны в пределах только того блока кода, в котором они определены.
Автоматические объекты
Локальные объекты, которые существуют только во время выполнения того блока, в котором они определены, являются автоматическими.
При входе в блок для подобных переменных выделяется память, а после завершения работы этого блока, выделенная память освобождается, а объекты удаляются.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
void print(int);
int main()
{
int z = 2;
print(z); // n=10
//n++; так сделать нельзя, так как n определена в функции print
return 0;
}
void print(int x)
{
int n = 5 * x;
// z++; так сделать нельзя, так как z определена в функции main
std::cout << "n=" << n << std::endl;
}
Здесь в функции print определена локальная переменная n. В функции main определена автоматическая переменная z. Вне своих функций эти переменные недоступны. Например, мы не можем использовать переменную n в функции main, так как ее область видимости ограничена функцией print. Соответственно также мы не можем использовать переменную z в функции print, так как эта переменная ограничена фукцией main.
Параметры функции также, как и локальные переменные, существуют, пока выполняется функция, вне функции они не доступны.
Подобным образом с помощью блока кода можно определить вложенные области видимости:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
int main()
{
int n = 2;
{
int x = 5;
std::cout << "x=" << x << std::endl;
n++; // так можно, так как n определена во внешнем контексте
}
//x++; // так сделать нельзя, так как x определена в блоке кода
std::cout << "n=" << n << std::endl;
return 0;
}
Для каждой области видимости доступны все те объекты, которые определены во внешней области видимости или во внешнем контексте. Глобальная область видимости является внешней для функции, поэтому функция может использовать глобальные переменные. А фукция является внешним контекстом для вложенного блока кода, поэтому блок кода может использовать переменную n, которая определена в функции вне этого блока. Однако переменные, определенные в блоке кода, вне этого блока использовать нельзя.
Сокрытие объектов
Локальные объекты, определенные внутри одного контекста, могут скрывать объекты с тем же именем, определенные во внешнем контексте:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
int n = 5;
int main()
{
int n = 10;
std::cout << "n=" << n << std::endl; // n=10
{
int n = 20;
std::cout << "n=" << n << std::endl; // n=20
}
return 0;
}
Здесь определено три переменных с именем n. Переменная n, определенная на уровне функции main (int n = 10;) скрывает глобальную переменную n. А переменная n, определенная на уровне блока, скрывает переменную, определенную на уровне функции main.
Статические объекты
Кроме автоматических есть особый тип локальных объектов - статические объекты. Они определяются на уровне функций с помощью ключевого слова static. Если автоматические переменные определяются и инициализируются при каждом входе в функцию, то статические переменные инициализируются только один раз, а при последующих вызовах функции используется старое значение статической переменной.
Например, пусть у нас будет функция со стандартной автоматической переменной:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
void display();
int main()
{
display();
display();
display();
return 0;
}
void display()
{
int i = 0;
i++;
std::cout << "i=" << i << std::endl;
}
Функция display вызывается три раза, и при каждом вызове программа повторно будет выделять память для переменной i, которая определена в функции. А после завершения работы display, память для переменной i будет освобождаться. Соответственно ее значение при каждом вызове будет неизменно:
i=1
i=1
i=1
Теперь сделаем переменную i статической:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
void display();
int main()
{
display();
display();
display();
return 0;
}
void display()
{
static int i = 0;
i++;
std::cout << "i=" << i << std::endl; // n=20
}
К переменной был добавлено ключевое слово static, поэтому при завершении работы функции display переменная не уничтожается, ее память не очищается, наоборот, она сохраняется в памяти. И соответственно результат работы программы будет иным:
i=1
i=2
i=3