В С++ есть понятия областей видимости переменных. Эта статья должна помочь немного разобраться начинающему программисту, что это такое.
Поскольку многие мои читатели скорее всего ещё далеко не ушли, в этой статье будет только поверхностное знакомство с областями видимости переменных.
На заметку:
Областью видимости или областью действия переменных называют участок кода, внутри которого с переменной можно работать.
Участки кода делятся не некоторые блоки кода: тело цикла, тело функции, просто тело и другие. В С++ эти тела обозначаются фигурными скобками. Так вот, можно использовать одну переменную, доступную всем телам сразу или переменные, доступные только внутри блоков кода. Простейший пример на самых простых блоках кода выглядит так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
usingstd::cout;
usingstd::cin;
intmain()
{
intmany_visible=10;//Переменная, будет доступна в обоих блоках кода
{//Блок кода #1
intvalue1=100;//Переменная, доступная только внутри блока #1
}
{//Блок кода #2
intvalue2=200;//Переменная, доступная только внутри блока #2
cout<<"many_visible: "<<many_visible<<'\n';//OK
// cout << value1 << '\n'; //Ошибка! Нет переменной value1
}
// cout << value1 << '\n'; //Ошибка! Нет переменной value1
// cout << value2 << '\n'; //Ошибка! Нет переменной value2
cin.get();
}
Будет ли доступна переменная в блоке кода или не будет — зависит от места объявления переменной. Всё, что объявляется внутри блока кода — доступно внутри блока и только внутри собственного блока. Конечно можно связать такую переменную с внешним миром, но изначально она принадлежит только внутреннему миру блока, внутри которого объявлена.
В показанном коде задействуется три переменные: many_visible, value1 и value2. Переменная many_visible объявлена внутри функции main и отдельные блоки кодов используются внутри функции main. Два созданных блока не связаны междц собой и скрывают своё нутро от постороннего мира, поэтому всё, что внутри них — внешнему миру закрыто. Поэтому последние две попытки вывода на экран значений переменных, созданных внутри некоторых блоков кода, приводит к ошибкам компиляции. Те переменные скрываются блоками от функции main. Это называется локализацией переменных.
Локальные переменные — это переменные некоторого блока кода, доступные только внутри собственного блока.
Таким образом у нас получается, что в коде две локальные переменные для самых простых блоков кода и одна локальная переменная для функции main. Для функции main локальна и переменная many_visible, и каждый блок, описанный внутри неё. Поэтому переменная many_visible легко внедряется в любой из блоков, описанных внутри main.
Это основа природы видимости переменных: в каких-то блоках кода переменные доступны, в каких-то нет. По правилам хорошего тона, нужно максимально локализовать переменные.
На этой картинке заливкой показано приблизительное представление областей видимости. Самая внутренняя область считается самой актуальной для блока. И актуальность происходит изнутри наружу. Если снаружи есть какая-то переменная, не закрытая каким-нибудь блоком, то такая переменная доступна.
Я надеюсь, что у меня получилось, объяснить, что это такое вообще. Теперь немного углубимся.
Если взять обычные функции, то внутри них могут быть внутренние, сокрытые функцией от внешнего мира переменные. Такие переменные называются локальными для функций переменными. А есть переменные, которые могут легко внедриться в любую функцию — такие переменные называют глобальными. Правда, использование глобальных переменных почти никем не приветствуется, но такие переменные иногда используют.
Глобальные переменные — это такие переменные, которые доступны по всей программе, в любом блоке кода.
Пример с глобальной переменной:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Глобальные переменные Borland C++ 3.1
#include <conio.h>
#include <iostream.h>
voidsum();//Прототип функции sum()
//Обратите внимание, что переменные объявляются вне функций
inti=100;//Глобальная переменная i. При объявлении запоминаем в i некоторое значение
inta;//Глобальная переменная a
intmain()
{
clrscr();
a=200;//так как a была объявлена вне функции - она глобальная и значит доступна по всему коду
sum();//Вызываем некоторую функцию
cin.get();
}
voidsum()
{
cout<<i<<endl;//Выводим значение переменной i на экран = 100
cout<<a<<endl;//Выводим значение переменной a на экран = 200. Значение 200 было записано в main
cout<<i+a<<endl;//Выводим значение i+a на экран = 300
}
Глобальная переменная объявляется вне тела функций и доступна она до конца программы. В приведенном примере вне функций было объявлено две переменные. К каждой из них можно обратиться в любом блоке программы. При этом, последнее запомненное значение таких переменных остается в памяти и доступно для последующей обработки. Просто немного поизучайте показанный пример. Персонально для функции sum переменных создано не было, но несмотря на это, я смог с помощью функции sum вывести верные значения переменных на экран. Смог, потому что объявил их вне тел функций, а значит сделал глобальными, т. е. доступными для любой функции (любого блока программы).
Кроме глобальных переменных существуют локальные переменные. Локальные для функций переменные объявляются внутри функций и доступны они только внутри своих функций. От внешнего мира функциями они скрываются.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Borland C++ 3.1 Локальные для функций переменные
#include <conio.h>
#include <iostream.h>
voidsum();//Прототип функции sum
intmain()
{
inta;//Объявили переменную внутри main, т.е. объявили локально
a=200;//Переменная объявленная внутри main доступна только и только внутри main
}
voidsum()
{
inti;//Объявили переменную i внутри sum. Другими словами объявили локальную переменную i
cout<<i<<endl;//Выводим на экран i
cout<<a<<endl;//Тут должна быть ошибка,
cout<<i+a<<endl;//a сокрыта от функции main
cin.get();
}
Ошибка в указанном месте возникает из-за того, что для функции sum нет никаких переменных, объявляемых внутри любой другой функции. Если программист объявляет переменную внутри одной функции, значит он предполагает, что с этой переменной будет работать только и только внутри той самой функции, в которой переменная объявлена и при необходимости подавать другим функциям в качестве аргумента. Такие переменные живут только внутри своих функций и недоступны для других участков кода. В отличие от предыдущего показанного примера, где была использована глобальная переменная, в этом примере глобальных переменных объявлено не было. Значит, по факту, для sum переменной a не существует в природе.
В разных областях видимости можно задавать переменным одинаковые названия. Обычно переменная из одной области не вмешивается в работу переменной из другой области. Просто в разных блоках кода сосуществуют две одноимённые переменные. Но иногда происходит попытка внедрения некоторой переменной в какой-то блок кода, когда в том блоке уже есть переменная с таким же названием, каким названа внедряемая переменная. В таком случае внутренняя переменная имеет приоритет над внедряемой и затеняет её. Внедряемая переменная также доступна, как была бы доступна и без одноимённой внутри блока переменной, но требуются дополнительные наши телодвижения.
На заметку:
Внутренняя переменная затеняет внешнюю переменную, если внешняя переменная имеет такое же имя как внутренняя и пытается внедриться в блок кода, внутри которого живёт внутренняя переменная.
Проще говоря, если в один блок кода происходит попытка закинуть переменную с таким именем, которое уже занято внутриблоковой переменной, то тогда мог бы быть конфликт имён. Но в С++ внутренние переменные первичны над внешними, поэтому для внутренней для блока переменной ничего не изменится, а вот работать со внешней нам придётся немного иначе, чем обычно.
Пример кода. Локальная переменная затеняет глобальную:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Borland C++ 3.1 Локальные переменные затеняют глобальные
#include <conio.h>
#include <iostream.h>
voidsum();//Прототип функции sum
voidnew_fun();//Прототип функции new_fun
inti=100;//Глобальная переменная i
intmain()
{
cout<<i<<endl;//В этом случае i глобальная, т.к. внутри main i объявлено не было i=100;
sum();//Вызывам некоторую функцию
new_fun();//Вызываем некоторую функцию
cin.get();
}
voidsum()
{
inti=20;//Переменная i локальная т.к. объявлена внутри sum.
//Действует только внутри sum
cout<<i<<endl;//Выводим на экран i.
//Локальная i затенила глобальную (действующая i=20).
//Глобальная i висит в памяти
cout<<::i<<endl;//Обращаемся к затенённой переменной
}
voidnew_fun()//Внутри new_fun переменных не объявлено,
//значит для new_fun существуют только глобальные переменные
{
cout<<i<<endl;//Выводм на экран глобальную i (i=100)
}
В случае, когда программист объявляет глобальную переменную и одноименную с ней локальную, локальная затеняет глобальную. При вызове функции с локальными переменными, локальные переменные по приоритету выше глобальных. Так как локальные переменные по приоритету выше, значит значения для вычислений берутся из них. По завершении функции глобальная переменная вновь приобретает силу. Это можно понять по приведенному примеру. Вне функций была объявлена некоторая переменная i (вне = глобальная), вместе с ней внутри функции sum была объявлена еще одна переменная i (внутри = локальная). Очень надеюсь, что этот пример нагляден вам и хорошо даёт понять выражение затенение переменной.
Когда мы вытаскивали затенённую переменную, мы использовали двоеточие перед названием переменной. Это двоеточие — это обозначение сущности из глобально пространства имён, т. е. мы явно указываем, что хотим глобальную переменную.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <conio.h>
#include <iostream.h>
inti=100;//Глобальная переменная i
intmain()
{
clrscr();
inti=50;//Локальная переменная i
cout<<i<<endl;//Обращение к локальной переменной (i=50)
cout<<::i<<endl;//Обращение к глобальной переменной (i=100) Использован глобальный оператор разрешения
cin.get();
}
Конечно в этой статье написано не всё, но статья ориентирована на совсем начинающих программистов, которым очень нужно растолковывать подробно некоторые простые вещи.
Писал ранее, но напомню. Глобальные переменные может быть удобнее использовать, чем локальные, но глобальных переменных нужно по максимуму избегать, предпочитая им локальные переменные.
Добавить комментарий