Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование.doc
Скачиваний:
40
Добавлен:
12.04.2015
Размер:
4.91 Mб
Скачать

Формат 1:

enum [имя_тега_перечисления] {список_перечисления}

описатель[,описатель...];

  • формат 2:

enum имя_тега_перечисления описатель [,описатель…];

Объявление перечисления задает тип объекта перечисления и определяет список именованных констант, называемый списком_перечисления. Значением каждого имени списка является некоторое целое число.

Объект типа перечисления может принимать значения одной из именованных констант списка. Именованные константы списка имеют тип int. Таким образом, память, соответствующая переменной перечисления, – это память, необходимая для размещения значения типаint.

В формате 1 имена и значения перечисления задаются в списке перечислений. Необязательное имя_тега_перечисления, – это идентификатор, который именует тег перечисления, определенный списком перечисления. Описатель именует переменную перечисления. В объявлении может быть задана более чем одна переменная типа перечисления. Список_перечисления содержит одну или несколько конструкций вида:

идентификатор [= константное_выражение]

Каждый идентификатор именует элемент перечисления. Все идентификаторы в списке enum должны быть уникальными. В случае отсутствия константного выражения первому идентификатору соответствует значение 0, следующему идентификатору – значение 1 и т.д. Имя константы перечисления эквивалентно ее значению.

Идентификатор, связанный с константным_выражением, принимает значение, задаваемое этим константным выражением. Константное выражение должно иметь тип int и может быть как положительным, так и отрицательным. Следующему идентификатору в списке присваивается значение, равное константному выражению плюс 1, если этот идентификатор не имеет своего константного выражения.

Использование элементов перечисления должно подчиняться следующим правилам:

  1. переменная может содержать повторяющиеся значения;

  2. идентификаторы в списке перечисления должны быть отличны от всех других идентификаторов в той же области видимости, включая имена обычных переменных и идентификаторы из других списков перечислений;

  3. имена типов перечислений должны быть отличны от других имен типов перечислений, структур и объединений в этой же области видимости;

  4. значение может следовать за последним элементом списка перечисления.

Примеры перечислимых объектов можно найти в разделе 2.

В зависимости от размещения объявления в исходном коде объект может иметь разные: контекст, класс памяти, продолжительность, видимость, компоновку.

Контекст – это часть программы, в которой данный объект существует, и к нему можно обращаться. Существует пять категорий контекста:

  1. блок (или локальный);

  2. функция;

  3. прототип функции;

  4. файл;

  5. класс (только для С++).

Контекст зависит от того, как и где объявлены идентификаторы.

Контекст блока (локальный) начинается с точки объявления имени и создания объекта и заканчивается в конце блока, содержащего данное объявление (такой блок называется объемлющим и заключен в фигурные скобки {}). Объявления параметров функции также имеют контекст блока, образующего тело этой функции.

Единственными идентификаторами, имеющими контекст функции, являются метки операторов. Имена меток могут быть использованы в операторах goto в любой точке функции, где объявлена данная метка. Метки объявляются неявно; для этого записывается имя_метки, затем идет двоеточие (:) и за ним оператор. Имена меток в пределах функции должны быть уникальными. Например:

strart: puts(“Начало блока”);

goto start;

Идентификаторы, объявленные в списке объявлений параметров в прототипе функции (не являющиеся частью определения функции) имеют контекст прототипа функции. Конец этого контекста совпадает с концом прототипа функции. Поэтому следующие объявления прототипов функции эквивалентны, так как цикл жизни объектов i,f и d начинается с момента их объявления и заканчивается закрытой круглой скобкой. Например:

int func(int i, float f, double d);

int func(int, float, double);

Идентификаторы с контекстом файла, называемые часто глобальными, объявляются вне всех блоков и классов; их контекст лежит между точкой объявления и концом исходного файла.

Классом можно считать именованный набор компонентов, включая структуры данных и функции, действующие с ними. Контекст класса относится к именам компонентов конкретного класса. В свою очередь, классы и их объекты имеют множество специальных правил доступа и определения контекста.

Чтобы различать идентификаторы объектов различного рода компилятор языка С++ устанавливает более сложный контекст, называемый «Пространства имен». Во избежание противоречий имена идентификаторов внутри одного пространства имен должны быть уникальными. В языке С++ имя должно быть объявлено до момента его первого использования в выражении.

Если в программе используется некоторая библиотека, то программист должен быть уверен, что имена созданных глобальных переменных не совпадают с именами объектов, взятых из библиотеки. Собирая программу с библиотеками разных производителей, нельзя гарантировать, что имена глобальных объектов не будут вступать в конфликт. Обойти эту проблему, названную проблемой засорения области видимости глобального пространства имен, можно посредством очень длинных имен, однако работать со слишком длинными идентификаторами для программистов утомительно.

Пространства имен помогают справиться с проблемой засорения более удобным

способом. Для их создания используется ключевое слово namespace, после которого записывается имя пользовательского пространства имен, а за ним следует блок в фигурных скобках, содержащий различные объявления. Каждое такое пространство представляет собой отдельную область видимости. Все объекты, объявленные внутри такого пространства имен, называются его членами.

Для доступа к члену созданного пространства используется оператор области видимости (::). Например, если создано пространство имен namespace abc и оно имеет объект х, то для доступа к этому объекту нужно обратиться abc :: x. Оператор области видимости может использоваться для ссылки на член глобального пространства имен, не имеющий имени, например, :: y.

Естественно, что каждый раз указывать такие специфицированные имена неудобно. Поэтому существуют механизмы, позволяющие облегчить использование пространств имен в программах. Это псевдонимы пространств имен, using-объявления и

using-директивы.

Программы, в которых используются пространства имен, обычно организуют следующим образом:

  1. объявления функций и объектов, являющихся членами пространства имен, помещают в заголовочный файл, который включается в каждый исходный файл, где они используются;

  2. определения этих членов помещают в исходный файл, содержащий реализацию. Для объявления объекта без его определения используется ключевое слово extern, как и в случае такого объявления в глобальной области видимости.

Псевдоним пространства имен используется для задания короткого синонима имени пространства. Объявление псевдонима начинается ключевым словом namespace, за которым следует короткий псевдоним, а за ним – знак равенства и исходное полное имя пространства.

Имеется механизм, позволяющий обращаться к членам пространства имен, используя их имена без имени пространства имен. Для этого применяются using-объявления. Using-объявление начинается ключевым словом using, за которым следует имя члена пространства. Using-объявление ведет себя подобно любому другому объявлению: оно имеет область видимости, и имя, введенное им, которые можно употреблять начиная с места объявления и до конца области видимости. Using-объявление может находиться в определенной области видимости, и, значит, можно точно указать, в каком месте программы те или иные члены разрешается употреблять без дополнительной квалификации.

Чтобы заставить программу работать с новой библиотекой помогают using-директивы, облегчающие переход на новую версию библиотеки, где впервые стали применяться пространства имен. Using-директива начинается ключевым словом using, за которым следует ключевое слово namespace, а затем имя некоторого пространства имен. Это имя должно ссылаться на определенное ранее пространство, иначе компилятор выдаст ошибку. Using-директива позволяет сделать все имена из этого пространства видимыми в неквалифицированной форме. Using-директивы очень полезны при переводе приложений на новые версии библиотек, использующие пространства имен.

Все компоненты стандартной библиотеки языка С++ находятся в пространстве имен std. Поэтому, при использовании одного пространства имен можно в исходный код ввести директиву:

using namespace std;

Для связи идентификаторов с объектами требуется, чтобы каждый идентификатор имел, кроме имени и типа, еще два атрибута: класс памяти и продолжительность. Компилятор языка C++ определяет эти атрибуты по явным или неявным объявлениям в исходном коде программы.

Класс памяти задает размещение объекта (в сегменте данных (static, extern), в регистре (register), в куче (heap) или стеке (auto)) и продолжительность, т.е. время его существования (все время работы программы, либо же при выполнении некоторых конкретных блоков кода). Класс памяти может быть установлен синтаксисом объявления, его расположением в исходном коде или обоими этими факторами.

Продолжительность, тесно связанная с классом памяти, определяет период, в течение которого объявленные идентификаторы имеют реальные физические объекты, расположенные в памяти. Следует делать различие между объектами, созданными при компиляции и при выполнении программы. Существует три вида продолжительности: статическая, локальная и динамическая.

Объектам со статической продолжительностью выделяется память сразу же в начале выполнения программы; память сохраняется до конца работы программы. Объекты со статической продолжительностью обычно размещаются в фиксированных сегментах данных. Все функции независимо от того, где они определены, являются объектами со статической продолжительностью. Также статическую продолжительность имеют все объекты с файловым контекстом. Другим переменным может быть задана статическая продолжительность путем использования явных спецификаторов класса памяти static или extern. Объекты со статической продолжительностью инициализируются в ноль (или пустое значение) при отсутствии явного спецификатора или в языке С++ конструктора.

Объекты с локальной продолжительностью всегда имеют локальный контекст, поскольку они не существуют вне своего объемлющего блока. Объекты с локальной продолжительностью, иначе называемые динамическими локальными переменными, имеют меньшую продолжительность. Они создаются в стеке (или в регистре) при входе в объемлющий их блок или функцию. При выходе программы из такого блока или функции они уничтожаются. Объекты с локальной продолжительностью должны быть инициализированы явно; в противном случае их начальное значение непредсказуемо. При объявлении переменных локальной продолжительности можно использовать спецификатор класса памяти auto, однако он является избыточным, поскольку auto для переменных, объявленных в блоке, всегда является умолчанием.

При объявлении переменных (например, int, char, float) с использованием спецификатора класса памяти register также подразумевается auto, однако компилятору при этом передается запрос (или рекомендация) о том, что желательно данный объект разместить в регистре. Если имеется свободный регистр, то компилятор языка C++ может для локальной переменной или переменной типа указатель выбрать его в качестве памяти. Если свободных регистров нет, то переменная распределяется как auto, или динамический локальный объект, без выдачи предупреждения и генерации ошибки.

Объекты с динамической продолжительностью создаются и уничтожаются специальными функциями при выполнении программы. Им выделяется память из специального резерва, называемого кучей (heap), при помощи либо стандартных библиотечных функций, как, например malloc(), либо при помощи операции new в языке С++. Соответствующая отмена распределения выполняется при помощи функций free() или операции delete. Например:

#include<stdio.h>

const double pi=3.1415926; // класс памяти – static, размещается в сегменте

// данных,

// продолжительность – с точки объявления до конца

// файла

void main(void)

{

float r=10; // класс памяти – auto, размещается в стеке, продолжительность –

// с точки объявления до конца блока

char * ptr=malloc(10); // класс памяти – heap, указывает на область памяти

// heap, продолжительность – с точки объявления

// до конца блока

free(ptr);

}

Видимостью идентификатора называется область исходного кода программы, из которого допустим нормальный доступ к связанному с идентификатором объекту. Обычно контекст и видимость совпадают, однако бывают случаи, когда объект временно скрыт вследствие наличия идентификатора с тем же именем. Объект при этом не прекращает своего существования, но исходный идентификатор не может служить для доступа к нему до тех пор, пока не закончится контекст дублирующего идентификатора.

Видимость не может выходить за пределы контекста; но контекст может превышать видимость. Например:

{

int i; char ch; // автоматическое распределение по умолчанию

i = 3; // объекты int i и char ch в контексте и видимы

...

{

double i; // объект double i в контексте и видим

i = 2.0e3; // объект int i в контексте, но скрыт

ch = 'A'; // объект char ch в контексте и видим

} // объект double i вне контекста

i += 1; // объект int i видим и равен 4

... // объект char ch в контексте, видим и равен 'A'

}

... // int i и char ch вне контекста

Выполняемая программа обычно создается компиляцией нескольких независимых единиц трансляции, а затем компоновкой получившихся объектных файлов с уже существующими библиотеками. Проблема возникает, когда один и тот же идентификатор объявлен в разных контекстах (например, в различных файлах), либо объявлен более одного раза в одном и том же контексте.

Компоновка – это процесс, который позволяет правильно связать каждое вхождение идентификатора с одним конкретным объектом или функцией. Все идентификаторы имеют один из трех атрибутов компоновки, тесно связанных с их контекстом: внешнюю компоновку, внутреннюю компоновку или отсутствие компоновки. Эти атрибуты определяются местоположением и форматом объявлений, вместе с явным (или неявным по умолчанию) использованием спецификатора класса памяти static или extern.