Область действия идентификаторов
Каждый программный объект имеет область действия, которая определяется видом и местом его объявления. Существуют следующие области действия:
Блок.Идентификаторы, описанные внутри блока, являются локальными. Область их действия начинается в точке определения и заканчивается в конце блока, видимость — в пределах блока и внутренних блоков, время жизни — до выхода из блока (после выхода из блока память освобождается).
Область видимости совпадает с областью действия за исключением ситуации, когда во вложенном блоке описана переменная с таким же именем. В этом случае внешняя переменная во вложенном блоке невидима, хотя он и входит в ее область действия. Если эта переменная глобальная, к ней можно обратиться, используя операцию доступа к области видимости ::. Способ обратиться к скрытой локальной переменной отсутствует.
Функция. Такую областьдействия, имеют метки операторов. В одной функции все метки должны различаться, но могут совпадать с метками других функций.
Прототип функции.Такую область действия имеют идентификаторы, указанные в списке параметров прототипа (объявления) функции.
Класс.Элементы структур, объединений и классов (за исключением статических элементов) являются видимыми лишь в их пределах. Они образуются при создании переменной указанного типа и разрушаются при ее уничтожении.
Файл.Идентификаторы, описанные вне любого блока, функции, класса или пространства имен, имеют глобальную видимость и постоянное время жизни и могут использоваться с момента их определения.
Поименованная область (пространство имен)
В каждой области действия различают пространства имен. Пространство имен — область, в пределах которой идентификатор должен быть уникальным.
В разных пространствах имена могут совпадать, поскольку разрешение ссылок осуществляется по контексту идентификатора в программе, например:
struct Node{
int Node;
int i;
} Node;
В данном случае противоречия нет, поскольку имена типа, переменной и элемента структуры относятся к разным пространствам.
Определено четыре класса идентификаторов, в пределах каждого из которых имена должны быть уникальными:
· имена переменных, функций, типов, определенных пользователем (typedef) и констант перечислений в пределах одной области видимости. Все они, кроме имен функций, могут быть переопределены во вложенных блоках;
· имена типов перечислений, структур, классов и объединений. Каждое имя должно отличаться от имен других типов в той же области видимости;
· элементы каждой структуры, класса и объединения. Имя элемента должно быть уникально внутри структуры, но может совпадать с именами элементов других структур;
· Метки образуют отдельное пространство имен.
Внешние объявления
Любая функция автоматически видна во всех модулях программы. Если требуется ограничить область действия функции файлом, в котором она описана, используется модификатор static.
Для того, чтобы сделать доступной в нескольких модулях переменную или константу, необходимо определить ее ровно в одном модуле как глобальную, а в других модулях объявить ее как внешнюю с помощью модификатора extern. Другой способ - поместить это объявление в заголовочный файл и включить его в нужные модули. Необходимо помнить, что объявление, в отличие от определения, не создает переменную. Объявление с extern не должно содержать инициализацию: если она присутствует, модификатор extern игнорируется.
Все описания одной и той же переменной должны быть согласованы.
Пример: описание двух глобальных переменных в файлах оnе.срр и two.cpp с помощью заголовочного файла my_header. h:
Файл my_header.h - внешние объявления
extern int а;
extern double b;
…
Файл оnе.срр
#include "my_header.h"
int a;
…
Файл two.cpp
#include "my_header.h"
double b;
…
Обе переменные доступны в файлах оnе.срр и two.cpp.
При описании типаследует придерживаться правила одного определения - тип, используемый в программе, должен быть определен ровно один раз. Как правило, это делается в заголовочном файле, который затем подключается к модулям, использующим этот тип.
Поименованнные области (пространства имен)
Можно явным образом задать пространство имен с помощью оператора namespace.
Объявление пространства имен имеет вид:
namespace [ имя_области ]{ /* Объявления */ }
Если имя области не задано, компилятор определяет его самостоятельно с помощью уникального идентификатора, различного для каждого модуля.
Поименованные области служат для логического группирования объявлений и ограничения доступа к ним. При использовании единственной глобальной области видимости формировать программу из отдельных частей очень сложно из-за возможного совпадения и конфликта имен.
Механизм пространств имен вместе с директивой #include обеспечивают необходимую при написании больших программ гибкость путем сочетания логического группирования связанных величин и ограничения доступа.
В любом функционально законченном фрагменте программы можно выделить интерфейсную часть (заголовки функций, описания типов), и часть реализации (вспомогательные переменные, функции и другие средства, доступ к которым извне не требуется. Пространства имен позволяют скрыть детали реализации и, следовательно, упростить структуру программы и уменьшить количество потенциальных ошибок. Продуманное разбиение программы на модули, четкая спецификация интерфейсов и ограничение доступа позволяют организовать эффективную работу над проектом группы программистов.
Объявление объекта в неименованной области равнозначно его описанию как глобального с модификатором static (глобальные статические переменные видны только в том модуле, в котором они описаны). Помещать объявления в такую область полезно для того, чтобы сохранить локальность кода (нельзя получить доступ из одного файла к элементу неименованной области другого файла).
Поименованная область может объявляться неоднократно, последующие объявления рассматриваются как расширения предыдущих. Объявление и соответсвующее изменение может осуществляться за рамками одного файла.
Пример:
namespace demo{
int i = 1;
int k = 0;
void funcl(int);
void func2(int) { /* ... */ }
}
namespace demo{ // Расширение
int i = 2; // Неверно - двойное определение
void func1(double); // Перегрузка
void func2(int); // Верно - повторное объявление
}
Объекты, объявленные внутри области, являются видимыми с момента объявления. К ним можно явно обращаться с помощью имени области и оператора доступа к области видимости ::, например:
demo::i = 100; demo::func2(10);
В объявлении поименованной области могут присутствовать как объявления, так и определения, но логично помещать в нее только объявления, а определять их позднее с помощью имени области и оператора доступа к области видимости ::, например:
void demo::funс1(int) { / * ... * / }
Это необходимо для разделения интерфейса и реализации. Таким способом нельзя объявить новый элемент пространства имен.
Если имя часто используется вне своего пространства, можно объявить его доступным с помощью оператораusing:
using demo::i:
После этого можно использовать имя без явного указания области.
Если требуется сделать доступными все имена из какой-либо области, используется оператор using namespace:
using namespace demo;
Операторы using и using namespace можно использовать и внутри объявления поименованной области, чтобы сделать в ней доступными объявления из другой области:
namespace Department_of_App1ied_Mathematics{
using demo::i;
...
}
Имена, объявленные в поименованной области явно или с помощью оператора using, имеют более высокий приоритет по отношению к именам, объявленным с помощью оператора using namespace. Это имеет значение при включении нескольких поименованных областей, содержащих совпадающие имена.
Короткие имена пространств имен могут войти в конфликт друг с другом, а длинные непрактичны при написании реального кода, поэтому допускается вводить синонимы имен:
namespace DAM = Department_of_Applied_Mathematics;