Это определит переменную bufSize
как константу. Любая попытка присвоить ей значение будет ошибкой:
bufSize = 512; //
Поскольку нельзя изменить значение константного объекта после создания, его следует инициализировать. Как обычно, инициализатор может быть выражением любой сложности:
const int i = get_size(); //
const int j = 42; //
const int k; //
Как уже упоминалось не раз, тип объекта определяет операции, которые можно с ним выполнять. Константный тип можно использовать для большинства, но не для всех операций, как и его неконстантный аналог. Ограничение одно — можно использовать только те операции, которые неспособны изменить объект. Например, тип const int
можно использовать в арифметических выражениях точно так же, как обычный неконстантный тип int
. Тип const int
преобразуется в тип bool
тем же способом, что и обычный тип int
, и т.д.
К операциям, не изменяющим значение объекта, относится инициализация. При использовании объекта для инициализации другого объекта не имеет значения, один или оба из них являются константами.
int i = 42;
const int ci = i; //
int j = ci; //
Хотя переменная ci
имеет тип const int
, ее значение имеет тип int
. Константность переменной ci
имеет значение только для операций, которые могли бы изменить ее значение. При копировании переменной ci
для инициализации переменной j
ее константность не имеет значения. Копирование объекта не изменяет его. Как только копия сделана, у нового объекта нет никакой дальнейшей связи с исходным объектом.
Когда константный объект инициализируется константой во время компиляции, такой как bufSize
в определении ниже, компилятор обычно заменяет используемую переменную ее значением во время компиляции.
const int bufSize = 512; //
Таким образом, компилятор создаст исполняемый код, использующий значение 512
в тех местах, где исходный код использует переменную bufSize
.
Чтобы заменить переменную значением, компилятор должен видеть ее инициализатор. При разделении программы на несколько файлов, в каждом из которых используется константа, необходим доступ к ее инициализатору. Для этого переменная должна быть определена в каждом файле, в котором используется ее значение (см. раздел 2.2.2). Для обеспечения такого поведения, но все же без повторных определений той же переменной, константные переменные определяются как локальные для файла. Определение константы с тем же именем в нескольких файлах подобно написанию определения для отдельных переменных в каждом файле.
Иногда константу необходимо совместно использовать в нескольких файлах, однако ее инициализатор не является константным выражением. Мы не хотим, чтобы компилятор создал отдельную переменную в каждом файле, константный объект должен вести себя как другие (не константные) переменные. В таком случае определить константу следует в одном файле, и объявить ее в других файлах, где она тоже используется.
Для определения единого экземпляра константной переменной используется ключевое слово extern
как в ее определении, так и в ее объявлениях.
//
//
extern const int bufSize = fcn();
//
extern const int bufSize; //
Здесь переменная bufSize
определяется и инициализируется в файле file_1.cc
. Поскольку это объявление включает инициализатор, оно (как обычно) является и определением. Но поскольку bufSize
константа, необходимо применить ключевое слово extern
, чтобы использовать ее в других файлах.
Объявление в заголовке file_1.h
также использует ключевое слово extern
. В данном случае это демонстрирует, что имя bufSize
не является локальным для этого файла и что его определение находится в другом месте.
extern
.
Упражнение 2.26. Что из приведенного ниже допустимо? Если что-то недопустимо, то почему?