---------------------------------------------------------------
Второе дополненное издание
---------------------------------------------------------------
Это справочное руководство описывает язык программирования С++ по
состоянии на май 1991. С++ - язык программирования общего назначения,
базирующийся на языке программирования С Ь.
Ь "The C Programming Language" B. Kernighan, D. Ritchie. Prentice
Hall, 1978, 1988.
Есть русский перевод: "Язык программирования С. Задачи по языку С"
Б. Керниган, Д. Ритчи, А. Фьюер. "Финансы и статистика". 1984
В дополнение к возможностям С язык С++ предоставляет классы, функции
подстановки, перегрузку операций, перегрузку имен функций, постоянные
типы, ссылки, операторы управления свободной памятью, проверку
параметров функций и приведение типов. Все расширения С суммируются
в $$R.18.1. Различия между С++ и ANSI C++ приведены в $$R.18.2 Ь.
Ь American National Standard X3.159-1989. Американский национальный
стандарт.
Расширения С++ версии 1985 года до данного описания суммируются в
$$R.18.1.2. Разделы, относящиеся к шаблонам типа ($$R.14) и
управлению особыми ситуациями ($$R.15), являются местами планируемых
расширений языка.
Это руководство содержит следующее:
1. Введение.
2. Соглашения о лексических понятиях.
3. Основные понятия.
4. Стандартные преобразования.
5. Выражения.
6. Операторы.
7. Описания.
8. Описатели.
9. Классы.
10. Производные классы.
11. Контроль доступа к членам.
12. Специальные функции-члены.
13. Перегрузка.
14. Шаблоны типов.
15. Управление особыми ситуациями.
16. Препроцессорная обработка.
Приложение A: Сводка синтаксиса
Приложение B: Совместимость
В записи синтаксиса языка в этом руководстве синтаксические понятия
обозначаются курсивом, а литеральные слова и символы шрифтом постоянной
ширины. Варианты перечисляются на отдельных строках, за исключением
тех немногих случаев, когда длинный список вариантов дается на одной
строке с пометкой "один из". Необязательный терминальный или
нетерминальный символ обозначается с помощью нижнего индекса "opt",
поэтому
{ выражение opt }
означает необязательное выражение, заключенное в фигурные скобки.
Программа на С++ состоит из одного или нескольких файлов ($$R.3.3).
С логической точки зрения файл транслируется за несколько проходов.
Первый проход состоит в препроцессорной обработке ($$R.16), на которой
происходит включение файлов и макроподстановка. Работа препроцессора
управляется с помощью команд, являющихся строками, первый символ
которых отличный от пробела есть # ($$R2.1). Результат работы
препроцессора есть последовательность лексем. Такую последовательность
лексем, т.е. файл после препроцессорной обработки, называют
единицей трансляции.
Существуют лексемы пяти видов: идентификаторы, служебные слова,
литералы, операции и различные разделители. Пробелы, вертикальная
и горизонтальная табуляция, конец строки, перевод строки и комментарии
(все вместе "обобщенные" пробелы), как указано ниже, игнорируются,
за исключением того, что они отделяют лексемы. Обобщенные пробелы
нужны, чтобы разделить стоящие рядом идентификаторы, служебные
слова и константы.
Если входной поток разобран на лексемы до данного символа, то
следующей лексемой считается лексема с максимально возможной длиной,
которая начинается с этого символа.
Комментарии
Символы /* начинают комментарий, который завершается символами */.
Такие комментарии не могут быть вложенными. Символы // начинают
комментарий, который завершается концом этой строки. Символы //,
/* и */ не имеют специального назначения в комментарии // и
рассматриваются как обычные символы. Аналогично символы // и /*
не имеют специального назначения внутри комментария /*.
Идентификатор - это последовательность букв и цифр произвольной длины.
Первый символ должен быть буквой, символ подчеркивания _ считается
буквой. Прописные и строчные буквы различаются. Все символы
существенны.
Перечисленные ниже идентификаторы фиксируются как служебные слова и
в другом смысле не могут использоваться:
asm continue float new signed try
auto default for operator sizeof typedef
break delete friend private static union
case do goto protected struct unsigned
catch double if public switch virtual
char else inline register template void
class enum int return this volatile
const extern long short throw while
В дополнение к этому идентификаторы, содержащие двойное подчеркивание
(__) резервируются для реализаций С++ и стандартных библиотек и
пользователи не должны употреблять их.
В представлении программы на С++ в кодировке ASCII используются
в качестве операций или разделителей следующие символы:
! % ^ & * ( ) - + = { } | ~
[ ] \ ; ' : " < > ? , . /
а следующие комбинации символов используются для задания операций:
-> ++ -- .* ->* << >> <= >= == != &&
|| *= /= %= += -= <<= >>= &= ^= |= ::
Каждая операция считается отдельной лексемой.
В дополнении к этому следующие символы резервируются для препроцессора:
# ##
Определенные, зависящие от реализации, свойства, такие как
тип операции sizeof ($$R5.3.2) или диапазоны базовых типов
($$R.3.6.1) определяются в стандартных заголовочных файлах
($$R.16.4)
<float.h> <limits.h> <stddef.h>
Эти файлы являются частью ANSI стандарта для С. Кроме того
заголовочные файлы
<new.h> <stdarg.h> <stdlib.h>
определяют типы самых важных библиотечных функций. Два последних
файла входят в ANSI стандарт для С, файл <new.h> относится только
к С++.
Есть несколько видов литералов (часто называемых "константами").
литерал:
целая константа
символьная константа
константа с плавающей точкой
строка литералов
Все целые константы, состоящие из последовательности цифр, считаются
десятичными (основание счисления десять), если только они не начинаются
с 0 (цифра ноль). Последовательность цифр, начинающаяся с 0,
считается восьмеричным целым (основание счисления восемь). Цифры 8 и 9
не являются восьмеричными. Последовательность цифр, начинающаяся с
0x или 0X, считается шестнадцатеричным целым (основание счисления
шестнадцать). Шестандцатеричные цифры могут состоять из символов
от a или A до f или F с десятичными значениями их от десяти до
пятнадцати. Например, число двенадцать можно записать как 12,
014 или 0XC.
Тип целой константы определяется ее представлением, значением и
окончанием. Если она десятичная и не имеет окончания, ее тип будет
первым подходящим для ее значения из следующих типов: int, long int,
unsigned long int. Если она восьмеричная или шестнадцатеричная и
не имеет окончания, ее тип будет первым подходящим для ее значения
из следующих: int, unsigned int, long int, unsigned long int.
Если она оканчивается символом u или U, ее тип будет первым подходящим
для ее значения из следующих: unsigned int, unsigned long int. Если
она оканчивается символом l или L, ее тип будет первым подходящим
для ее значения из следующих: long int, unsigned long int. Если
она оканчивается на ul, lu, uL, Lu, Ul, lU, UL или LU, ее типом
будет unsigned long int.
Символьной константой является один или несколько символов, заключенные
в одиночные кавычки, например 'x'. Константа из одного символа имеет
тип char. Значение константы из одного символа есть порядковый номер
символа в таблице кодировки символов на данной машине. Символьные
константы из нескольких символов имеют тип int. Значение такой
константы зависит от реализации.
Некоторые символы, не имеющие графического представления, как
одиночная кавычка ',двойная кавычка ", знак вопроса ?, обратная
дробная черта \, можно представлять комбинацией символов (начинающейся
с \) в соответствии с приводимой ниже таблицей:
конец строки NL (LF) \n
горизонтальная табуляция HT \t
вертикальная табуляция VT \v
шаг назад BS \b
возврат каретки CR \r
перевод формата (авторегистр) FF \f
сигнал BEL \a
обратная дробная черта \ \\
знак вопроса ? \?
одиночная кавычка ' \'
двойная кавычка " \"
восьмеричное число ooo \ooo
шестнадцатеричное число hhh \xhhh
Если за обратной дробной чертой следует символ, отличный от
перечисленных, результат неопределен.
Комбинация \ooo состоит из обратной дробной черты, а которой
следуют одна, две или три восьмеричные цифры. Считается, что они
определяют значение искомого символа. Комбинация \xhhh состоит из
из обратной дробной черты, за которой следует x, а за ним, в свою
очередь, следует последовательность шестнадцатеричных цифр.
Считается, что она задает значение искомого символа. Нет ограничения
на длину этой последовательности шестнадцатеричных цифр.
Последовательность восьмеричных или шестнадцатеричных цифр
оканчивается, когда встречается первый символ, который не есть
восьмеричная или шестнадцатеричная цифра соответственно. Если
значение символьной константы превосходит максимальное из char,
то оно определяется реализацией.
Символьная константа, которой непосредственно предшествует
буква L, является широкой символьной константой, например, L'ab'.
Такие константы имеют тип wchar_t, являющийся целочисленным типом
($$R.3.6.1), определенном в стандартном заголовочном файле
<stddef.h>. Широкие символы предназначены для такого набора
символов, где значение символа не помещается в один байт.
Константы с плавающей точкой состоят из целой части, символа
точка, дробной части, e или E, целого показателя с возможным
знаком и возможным окончанием, указывающим тип. Целая и дробная
части состоят из последовательности десятичных (основание
счисления десять) цифр. Или целая часть, или дробная часть
(но не обе) могут отсутствовать. Или точка, или символ e (или E)
вместе с показателем могут отсутствовать (но не оба). Тип
константы с плавающей точкой есть double, если только он не
задан явно с помощью окончания. Окончания f или F задают тип
float, окончания l или L задают тип long double.
Строка литералов есть последовательность символов (как они определены
в $$R.2.5.2), заключенная в двойные кавычки, т.е. "...". Строка
имеет тип "массив символов" и класс памяти static ($$R.3.5), она
инициализируется заданными символами. Будут ли все строки различны
(т.е. хранится в отдельных объектах), определяется реализацией.
Соседние строки литералов конкатенируются. Символы в строках,
полученных при конкатенации, хранятся отдельно. Например, после
конкатенации
"\xA" "B"
строка будет содержать два символа '\xA' и 'B' (а не один
шестнадцатеричный символ '\xAB').
После всех необходимых конкатенаций к строке добавляется
символ '\0', чтобы программа, читающая строку, могла определить
ее конец. Размер строки равен числу всех ее символов, включая
символ завершитель строки. Внутри строки перед символом двойной
кавычки " должен идти символ \.
Строка литералов, перед которой непосредственно идет символ L,
считается широкосимвольной строкой, например, L"asdf". Такая
строка имеет тип "массив элементов типа wchar_t", где wchar_t
целочисленный тип, определенный в стандартном заголовочном файле
<stddef.h>. Результат конкатенации обычных и широкосимвольных
строк литералов неопределен.
Имя обозначает объект, функцию, множество функций, элемент
перечисления, тип, член класса, шаблон типа, значение или метку.
Имя становится известно в программе с помощью описания. Имя можно
использовать только в пределах части программы, называемой областью
видимости имени. Имя имеет тип, который задает его использование.
Имя, используемое в более чем одной единице трансляции, может
обозначать один и тот же (а может и разные) объект, функцию, тип,
шаблон типа или значение, в зависимости от компоновки ($$R.3.3)
этих единиц трансляции.
Объект имеет область для его хранения ($$R.3.7). Поименованный
объект имеет класс памяти ($$R.3.5), который определяет его время
жизни. Интерпретация значений, хранящихся в объекте, определяется
типом выражения, задающего доступ к объекту.
Описание ($$r.7) делает известным в программе одно или несколько
имен. Описание считается определением, если только оно не описывает
функцию без задания ее тела ($$R.8.3), не содержит описателя
extern ($$R.7.11), не имеет части инициализации или тела функции,
не является описанием статического члена данных в описании класса
($$R.9.4), не является описанием имени класса ($$R.9.1), не является
описанием typedef ($$R.7.1.3). Ниже приведены примеры определений:
int a;
extern const c = 1;
int f(int x) { return x+a; }
struct S { int a; int b; };
enum { up, down };
тогда как ниже следуют только описания:
extern int a;
extern const c;
int f(int);
struct S;
typedef int Int;
Для каждого объекта, функции, класса и элемента перечисления,
используемых в программе, должно быть только одно определение
($$R.3.3). Если функция никогда не вызывается и ее адрес никогда
не используется, ее не нужно определять. Аналогично, если имя класса
используется только так, что не требуется знать определения класса,
то такой класс не надо определять.
Существует четыре области видимости: локальная, функция, файл и класс.
Локальная: Имя, описанное в блоке ($$R.6.3), является локальным
в этом блоке и может использоваться только в нем и в блоках,
содержащихся в этом блоке и появляющихся после момента описания.
Имена формальных параметров рассматриваются, как если бы они были
описаны в самом объемлющем блоке этой функции.
Функция: Метки ($$R.6.1) можно использовать повсюду в функции,
в которой они описаны. Только метки имеют область видимости,
совпадающую с функцией.
Файл: Имя описанное вне всех блоков ($$R.6.3) и классов ($$R.9)
имеет область видимости файл и может быть использовано в единице
трансляции, в которой оно появляется после момента описания. Имена,
описанные с файловой областью видимости, называются глобальными.
Класс: Имя члена класса является локальным в своем классе и
оно может быть использовано только в функции-члене этого класса
($$R.9.3), или после операции . , применяемой к объекту данного
класса ($$R.5.2.4) или объекту производного класса($$R.10),
или после операции ->, применяемой к указателю на объект данного
класса ($$R.5.2.4) или на объект производного класса, или после
операции разрешения :: ($$R.5.1), примененной к имени данного
или производного класса. Имя, введенное с помощью операции
friend ($$R.11.4), принадлежит той же области определенности,
что и класс, содержащий описание friend. Класс, впервые
описанный в операторе return или в типе параметра, принадлежит
к глобальной области видимости.
Специальные соглашения действуют на имена, введенные при описании
параметров функции ($$R.8.2.5) и в описаниях friend ($$R.11.4).
Имя может быть скрыто явным описанием того же имени в объемлющем
блоке или классе. Скрытое имя члена класса все-таки можно
использовать, если оно предваряется именем класса, к которому
применена операция :: ($$R.4.1, $$R.9.4, $$R.10). Скрытое имя объекта,
функции, типа или элемента перечисления с файловой областью видимости
можно использовать, если оно предваряется унарной операцией ::
($$R.5.1). В дополнении к этому, имя класса ($$R.9.1) может быть
скрыто именем объекта, функции или элемента перечисления, имеющего
ту же область видимости. Если класс и объект, или функция, или
элемент перечисления описаны (в любом порядке) с одинаковым именем
в одной области видимости, то имя класса становится скрытым. Имя
класса, скрытое в локальной области видимости или в области
видимости класса именем объекта, функции или элемента перечисления,
все-таки можно использовать, если предварить его подходящей
спецификацией class, struct или union ($$R.7.1.6). Аналогично,
скрытое имя элемента перечисления можно использовать, если
предварить его спецификацией типа enum ($$R.7.1.6). В $$R.10.4
приводится сводка правил области видимости.
Моментом описания имени считается момент завершения описателя имени
($$R.8), предшествующей части инициализации (если она есть).
Например,
int x = 12;
{ int x = x; }
Здесь второе x инициализируется своим собственным (неопределенным)
значением.
Моментом описания элемента перечисления считается момент сразу
после появления его идентификатора, например:
enum { x = x };
Здесь элемент перечисления x опять инициализируется своим собственным
(неопределенным) значением.
Программа состоит из одного или нескольких файлов, связываемых вместе
($$R.2). Файл состоит из последовательности описаний.
Имя с файловой областью видимости, которое явно описано как
static, является локальным в своей единице трансляции и может
использоваться для именования объектов, функций и т.п. в других
единицах трансляции. Говорят, что такие имена имеют внутреннее
связывание. Имя с файловой областью видимости, которое явно описано
со спецификацией inline, является локальным в своей единице
трансляции. Имя с файловой областью видимости, которое явно описано
со спецификацией const и не описано явно как extern, считается
локальным в своей единице трансляции. То же верно для имени класса,
которое не использовалось в нелокальных для данной единицы
трансляции описаниях объекта, функции или класса, и который не
имеет статических членов ($$R.9.4), не имеет функций-членов, кроме
подстановок ($$R.9.3.2). Всякое описание некоторого имени с
файловой областью видимости, которое не описано одним из перечисленных
способов так, чтобы иметь внутреннее связывание, в многофайловой
программе обозначает один и тот же объект ($$R.3.7), функцию
($$R.8.2.5) или класс ($$R.9). Такие имена называются внешними или
говорят, что они имеют внешнее связывание. В частности, поскольку
нельзя описать имя класса как static, всякое употребление имени
некоторого класса с файловой областью видимости, который (класс)
использовался для описания объекта или функции с внешним связыванием,
или же который имеет статический член или функцию-член,
не являющуюся подстановкой, будет обозначать один и тот же класс.
Имена определяемых типов (typedef $$R.7.13), элементы перечисления
($$R.7.2) или имена шаблонов типа ($$R.14) не имеют внешнего
связывания.
Статические члены класса ($$R.9.4) допускают внешнее связывание.
Функции-члены, не являющиеся подстановкой, допускают внешнее
связывание. Функции-члены, являющиеся подстановкой, должны иметь
в точности одно определение в программе.
Локальные имена ($$R.3.2), явно описанные со спецификацией
extern, имеют внешнее связывание, если только они уже не были
описаны как static ($$R.7.1.1).
Типы, используемые во всех описаниях некоторого внешнего имени,
должны совпадать, за исключением использования имен определяемых
типов ($$R.7.1.3) и указания границ массивов ($$R.8.2.4).
Должно быть в точности одно определение для каждой функции, объекта,
класса и элемента перечисления, используемых в программе. Однако,
если функция никогда не вызывается и ее адрес никогда не используется,
ее не нужно определять. Аналогично, если имя класса используется
только таким образом, что не требуется знать определение класса,
то класс не нужно определять.
Область видимости функции может быть только файл или класс.
С помощью спецификации связывания можно добиться связывания с
описаниями на другом языке ($$R.7.4).
Программа должна содержать функцию с именем main(). Ей приписывается
роль начала программы. Эта функция не является предопределенной
для транслятора, она не может быть перегружена, а ее тип зависит
от реализации. Предполагается, что любая реализация должна
допускать два приведенных ниже определения и что можно добавлять
после argv любые параметры. Функция main может определяться так
int main() { /* ... */ }
или
int main(int argc, char* argv[]) { /* ... */ }
В последнем определении argc задает число параметров, передаваемых
программе окружением, в котором она выполняется. Если argc не
равно нулю, параметры должны передаваться как строки, завершающиеся
символом '\0', с помощью argv[0] до argv[argc-1], причем
argv[0] должно быть именем, под которым программа была запущена,
или "". Должно гарантироваться, что argv[argc]==0.
Функция main() не должна вызываться в программе. Связывание
main() ($$R.3.3) зависит от реализации. Нельзя получать адрес
main() и не следует описывать ее как inline или static.
Вызов функции
void exit(int);
описанной в <stdlib.h>, завершает программу. Значение параметра
передается окружению программы в качестве результата программы.
Инициализация нелокальных статических объектов ($$R.3.5)
единицы трансляции происходит прежде первого обращения к функции
или объекту, определенному в этой единице трансляции. Эта
инициализация ($$R.8.4, $$R.9.4, &&R.12.1, $$R.12.6.1) может
быть проведена перед выполнением первого оператора main() или
отложена до любого момента, предшествующего первому использованию
функции или объекта, определенных в данной единице трансляции.
Все статические объекты по умолчанию инициализируются нулем ($$R.8.4)
прежде любой динамической (во времени выполнения программы)
инициализации. Больше никаких требований на порядок инициализации
объектов из различных единиц трансляции не налагается. Инициализация
локальных и статических объектов описана в $$R.8.4.
Деструкторы ($$R.12.4) для инициализированных статических
объектов вызываются при возврате из main() или при вызове exit().
Уничтожение происходит в обратном порядке по сравнению с
инициализацией. С помощью функции atexit() из <stdlib.h> можно
указать функцию, которую нужно вызывать при выходе из программы.
Если было обращение к функции atexit(), объекты, инициализированные
до вызова atexit(), не должны уничтожаться до тех пор, пока не
произойдет вызов функции, указанной в atexit(). Если реализация С++
сосуществует с реализацией С, все действия, которые должны были
произойти после вызова функции, заданной в atexit(), происходят
только после вызова всех деструкторов.
Вызов функции
void abort();
описанной в <stdlib.h>, завершает программу без выполнения
деструкторов статических объектов и без вызова функций, заданных
в atexit().
Существует два описываемых класса памяти: автоматический и статический.
Автоматические объекты становятся локальными при передаче
управления в каждый блок.
Статические объекты существуют и сохраняют свое значение во все
время выполнения программы.
Автоматические объекты инициализируются ($$R.12.1) всякий раз,
когда управление переходит в блок, где они определены и уничтожаются
($$R.12.4) по выходе из этого блока ($$R.6.7).
Поименованный автоматический объект не должен быть уничтожен
до окончания его блока, точно так же, как не может быть исключен
поименованный автоматический объект класса, имеющего конструктор
или деструктор с побочным эффектом, даже если кажется, что этот
объект не используется.
Аналогично, глобальный объект класса с конструктором или
деструктором, имеющими побочный эффект, не может быть исключен,
даже если кажется, что он не используется.
Статические объекты инициализируются и уничтожаются в
соответствии с описанием в $$R.3.4 и $$R.6.7. С некоторыми объектами
не связано никакого имени, см. $$R.5.3.3 и $$R.12.2. Все глобальные
объекты имеют класс памяти статический. Локальным объектам и членам
класса можно предать класс памяти статический с помощью явного
использования спецификации класса памяти static ($$R.7.1.1).
Существуют два вида типов: основные и производные.
Существует несколько основных типов. В стандартном заголовочном
файле <limits.h> задаются в зависимости от реализации минимальные и
максимальные значения каждого типа.
Объекты, описанные как символы (char), могут хранить любой
элемент из базового набора символов данной машины. Если символ
этого набора хранится в символьной переменной, то ее значение
равно целому значению кода этого символа. Символы могут явно
описываться как unsigned или signed. Обычный char, signed char и
unsigned char являются тремя различными типами. Для всех этих
трех типов требуется одинаковый объем памяти.
С помощью описаний short int, int и long int можно определить
целые трех различных размеров. Для длинных целых требуется памяти
не меньше чем для коротких целых, но в реализации или короткие
целые, или длинные целые, или и те и другие могут оказаться
эквивалентными обычным целым. Обычные целые имеют размер,
определяемый системой команд, размеры других целых определяются
конкретными потребностями.
Для каждого из типов signed char, short, int и long существует
соответствующий беззнаковый тип, который занимает тот же объем
памяти и удовлетворяет тем же требованиям выравнивания.
Требование выравнивание - это ограничение на значение указателя
на данный объект, которое накладывает реализация ($$R.5.4).
Беззнаковые целые, описанные как unsigned, подчиняются законом
арифметики по модулю 2@n, где n число битов, используемое для
представления значения. Отсюда следует, что в арифметике беззнаковых
не возникает переполнения.
Существует три типа с плавающей точкой: float, double и long double.
Тип double гарантирует не меньшую точность представления, чем
float, а тип long double гарантирует точность не меньше, чем у
double. Характеристики основных типов с плавающей точкой определяются
в соответствии с реализацией в стандартном заголовочном файле
<float.h>.
Типы char, int любых размеров и тип перечисления ($$R.7.2)
называются целочисленными типами. Целочисленные типы вместе с
типами с плавающей точкой образуют арифметические типы.
Тип void задает пустое множество значений. Он используется для
обозначения типа функций, которые не возвращают результат. Нельзя
описывать объекты с типом void. Любое выражение можно явно
преобразовать к типу void ($$R.5.4), получившееся выражение можно
использовать только как выражение-оператор ($$R.6.2), как
Второе дополненное издание
---------------------------------------------------------------
Это справочное руководство описывает язык программирования С++ по
состоянии на май 1991. С++ - язык программирования общего назначения,
базирующийся на языке программирования С Ь.
Ь "The C Programming Language" B. Kernighan, D. Ritchie. Prentice
Hall, 1978, 1988.
Есть русский перевод: "Язык программирования С. Задачи по языку С"
Б. Керниган, Д. Ритчи, А. Фьюер. "Финансы и статистика". 1984
В дополнение к возможностям С язык С++ предоставляет классы, функции
подстановки, перегрузку операций, перегрузку имен функций, постоянные
типы, ссылки, операторы управления свободной памятью, проверку
параметров функций и приведение типов. Все расширения С суммируются
в $$R.18.1. Различия между С++ и ANSI C++ приведены в $$R.18.2 Ь.
Ь American National Standard X3.159-1989. Американский национальный
стандарт.
Расширения С++ версии 1985 года до данного описания суммируются в
$$R.18.1.2. Разделы, относящиеся к шаблонам типа ($$R.14) и
управлению особыми ситуациями ($$R.15), являются местами планируемых
расширений языка.
Это руководство содержит следующее:
1. Введение.
2. Соглашения о лексических понятиях.
3. Основные понятия.
4. Стандартные преобразования.
5. Выражения.
6. Операторы.
7. Описания.
8. Описатели.
9. Классы.
10. Производные классы.
11. Контроль доступа к членам.
12. Специальные функции-члены.
13. Перегрузка.
14. Шаблоны типов.
15. Управление особыми ситуациями.
16. Препроцессорная обработка.
Приложение A: Сводка синтаксиса
Приложение B: Совместимость
В записи синтаксиса языка в этом руководстве синтаксические понятия
обозначаются курсивом, а литеральные слова и символы шрифтом постоянной
ширины. Варианты перечисляются на отдельных строках, за исключением
тех немногих случаев, когда длинный список вариантов дается на одной
строке с пометкой "один из". Необязательный терминальный или
нетерминальный символ обозначается с помощью нижнего индекса "opt",
поэтому
{ выражение opt }
означает необязательное выражение, заключенное в фигурные скобки.
Программа на С++ состоит из одного или нескольких файлов ($$R.3.3).
С логической точки зрения файл транслируется за несколько проходов.
Первый проход состоит в препроцессорной обработке ($$R.16), на которой
происходит включение файлов и макроподстановка. Работа препроцессора
управляется с помощью команд, являющихся строками, первый символ
которых отличный от пробела есть # ($$R2.1). Результат работы
препроцессора есть последовательность лексем. Такую последовательность
лексем, т.е. файл после препроцессорной обработки, называют
единицей трансляции.
Существуют лексемы пяти видов: идентификаторы, служебные слова,
литералы, операции и различные разделители. Пробелы, вертикальная
и горизонтальная табуляция, конец строки, перевод строки и комментарии
(все вместе "обобщенные" пробелы), как указано ниже, игнорируются,
за исключением того, что они отделяют лексемы. Обобщенные пробелы
нужны, чтобы разделить стоящие рядом идентификаторы, служебные
слова и константы.
Если входной поток разобран на лексемы до данного символа, то
следующей лексемой считается лексема с максимально возможной длиной,
которая начинается с этого символа.
Комментарии
Символы /* начинают комментарий, который завершается символами */.
Такие комментарии не могут быть вложенными. Символы // начинают
комментарий, который завершается концом этой строки. Символы //,
/* и */ не имеют специального назначения в комментарии // и
рассматриваются как обычные символы. Аналогично символы // и /*
не имеют специального назначения внутри комментария /*.
Идентификатор - это последовательность букв и цифр произвольной длины.
Первый символ должен быть буквой, символ подчеркивания _ считается
буквой. Прописные и строчные буквы различаются. Все символы
существенны.
Перечисленные ниже идентификаторы фиксируются как служебные слова и
в другом смысле не могут использоваться:
asm continue float new signed try
auto default for operator sizeof typedef
break delete friend private static union
case do goto protected struct unsigned
catch double if public switch virtual
char else inline register template void
class enum int return this volatile
const extern long short throw while
В дополнение к этому идентификаторы, содержащие двойное подчеркивание
(__) резервируются для реализаций С++ и стандартных библиотек и
пользователи не должны употреблять их.
В представлении программы на С++ в кодировке ASCII используются
в качестве операций или разделителей следующие символы:
! % ^ & * ( ) - + = { } | ~
[ ] \ ; ' : " < > ? , . /
а следующие комбинации символов используются для задания операций:
-> ++ -- .* ->* << >> <= >= == != &&
|| *= /= %= += -= <<= >>= &= ^= |= ::
Каждая операция считается отдельной лексемой.
В дополнении к этому следующие символы резервируются для препроцессора:
# ##
Определенные, зависящие от реализации, свойства, такие как
тип операции sizeof ($$R5.3.2) или диапазоны базовых типов
($$R.3.6.1) определяются в стандартных заголовочных файлах
($$R.16.4)
<float.h> <limits.h> <stddef.h>
Эти файлы являются частью ANSI стандарта для С. Кроме того
заголовочные файлы
<new.h> <stdarg.h> <stdlib.h>
определяют типы самых важных библиотечных функций. Два последних
файла входят в ANSI стандарт для С, файл <new.h> относится только
к С++.
Есть несколько видов литералов (часто называемых "константами").
литерал:
целая константа
символьная константа
константа с плавающей точкой
строка литералов
Все целые константы, состоящие из последовательности цифр, считаются
десятичными (основание счисления десять), если только они не начинаются
с 0 (цифра ноль). Последовательность цифр, начинающаяся с 0,
считается восьмеричным целым (основание счисления восемь). Цифры 8 и 9
не являются восьмеричными. Последовательность цифр, начинающаяся с
0x или 0X, считается шестнадцатеричным целым (основание счисления
шестнадцать). Шестандцатеричные цифры могут состоять из символов
от a или A до f или F с десятичными значениями их от десяти до
пятнадцати. Например, число двенадцать можно записать как 12,
014 или 0XC.
Тип целой константы определяется ее представлением, значением и
окончанием. Если она десятичная и не имеет окончания, ее тип будет
первым подходящим для ее значения из следующих типов: int, long int,
unsigned long int. Если она восьмеричная или шестнадцатеричная и
не имеет окончания, ее тип будет первым подходящим для ее значения
из следующих: int, unsigned int, long int, unsigned long int.
Если она оканчивается символом u или U, ее тип будет первым подходящим
для ее значения из следующих: unsigned int, unsigned long int. Если
она оканчивается символом l или L, ее тип будет первым подходящим
для ее значения из следующих: long int, unsigned long int. Если
она оканчивается на ul, lu, uL, Lu, Ul, lU, UL или LU, ее типом
будет unsigned long int.
Символьной константой является один или несколько символов, заключенные
в одиночные кавычки, например 'x'. Константа из одного символа имеет
тип char. Значение константы из одного символа есть порядковый номер
символа в таблице кодировки символов на данной машине. Символьные
константы из нескольких символов имеют тип int. Значение такой
константы зависит от реализации.
Некоторые символы, не имеющие графического представления, как
одиночная кавычка ',двойная кавычка ", знак вопроса ?, обратная
дробная черта \, можно представлять комбинацией символов (начинающейся
с \) в соответствии с приводимой ниже таблицей:
конец строки NL (LF) \n
горизонтальная табуляция HT \t
вертикальная табуляция VT \v
шаг назад BS \b
возврат каретки CR \r
перевод формата (авторегистр) FF \f
сигнал BEL \a
обратная дробная черта \ \\
знак вопроса ? \?
одиночная кавычка ' \'
двойная кавычка " \"
восьмеричное число ooo \ooo
шестнадцатеричное число hhh \xhhh
Если за обратной дробной чертой следует символ, отличный от
перечисленных, результат неопределен.
Комбинация \ooo состоит из обратной дробной черты, а которой
следуют одна, две или три восьмеричные цифры. Считается, что они
определяют значение искомого символа. Комбинация \xhhh состоит из
из обратной дробной черты, за которой следует x, а за ним, в свою
очередь, следует последовательность шестнадцатеричных цифр.
Считается, что она задает значение искомого символа. Нет ограничения
на длину этой последовательности шестнадцатеричных цифр.
Последовательность восьмеричных или шестнадцатеричных цифр
оканчивается, когда встречается первый символ, который не есть
восьмеричная или шестнадцатеричная цифра соответственно. Если
значение символьной константы превосходит максимальное из char,
то оно определяется реализацией.
Символьная константа, которой непосредственно предшествует
буква L, является широкой символьной константой, например, L'ab'.
Такие константы имеют тип wchar_t, являющийся целочисленным типом
($$R.3.6.1), определенном в стандартном заголовочном файле
<stddef.h>. Широкие символы предназначены для такого набора
символов, где значение символа не помещается в один байт.
Константы с плавающей точкой состоят из целой части, символа
точка, дробной части, e или E, целого показателя с возможным
знаком и возможным окончанием, указывающим тип. Целая и дробная
части состоят из последовательности десятичных (основание
счисления десять) цифр. Или целая часть, или дробная часть
(но не обе) могут отсутствовать. Или точка, или символ e (или E)
вместе с показателем могут отсутствовать (но не оба). Тип
константы с плавающей точкой есть double, если только он не
задан явно с помощью окончания. Окончания f или F задают тип
float, окончания l или L задают тип long double.
Строка литералов есть последовательность символов (как они определены
в $$R.2.5.2), заключенная в двойные кавычки, т.е. "...". Строка
имеет тип "массив символов" и класс памяти static ($$R.3.5), она
инициализируется заданными символами. Будут ли все строки различны
(т.е. хранится в отдельных объектах), определяется реализацией.
Соседние строки литералов конкатенируются. Символы в строках,
полученных при конкатенации, хранятся отдельно. Например, после
конкатенации
"\xA" "B"
строка будет содержать два символа '\xA' и 'B' (а не один
шестнадцатеричный символ '\xAB').
После всех необходимых конкатенаций к строке добавляется
символ '\0', чтобы программа, читающая строку, могла определить
ее конец. Размер строки равен числу всех ее символов, включая
символ завершитель строки. Внутри строки перед символом двойной
кавычки " должен идти символ \.
Строка литералов, перед которой непосредственно идет символ L,
считается широкосимвольной строкой, например, L"asdf". Такая
строка имеет тип "массив элементов типа wchar_t", где wchar_t
целочисленный тип, определенный в стандартном заголовочном файле
<stddef.h>. Результат конкатенации обычных и широкосимвольных
строк литералов неопределен.
Имя обозначает объект, функцию, множество функций, элемент
перечисления, тип, член класса, шаблон типа, значение или метку.
Имя становится известно в программе с помощью описания. Имя можно
использовать только в пределах части программы, называемой областью
видимости имени. Имя имеет тип, который задает его использование.
Имя, используемое в более чем одной единице трансляции, может
обозначать один и тот же (а может и разные) объект, функцию, тип,
шаблон типа или значение, в зависимости от компоновки ($$R.3.3)
этих единиц трансляции.
Объект имеет область для его хранения ($$R.3.7). Поименованный
объект имеет класс памяти ($$R.3.5), который определяет его время
жизни. Интерпретация значений, хранящихся в объекте, определяется
типом выражения, задающего доступ к объекту.
Описание ($$r.7) делает известным в программе одно или несколько
имен. Описание считается определением, если только оно не описывает
функцию без задания ее тела ($$R.8.3), не содержит описателя
extern ($$R.7.11), не имеет части инициализации или тела функции,
не является описанием статического члена данных в описании класса
($$R.9.4), не является описанием имени класса ($$R.9.1), не является
описанием typedef ($$R.7.1.3). Ниже приведены примеры определений:
int a;
extern const c = 1;
int f(int x) { return x+a; }
struct S { int a; int b; };
enum { up, down };
тогда как ниже следуют только описания:
extern int a;
extern const c;
int f(int);
struct S;
typedef int Int;
Для каждого объекта, функции, класса и элемента перечисления,
используемых в программе, должно быть только одно определение
($$R.3.3). Если функция никогда не вызывается и ее адрес никогда
не используется, ее не нужно определять. Аналогично, если имя класса
используется только так, что не требуется знать определения класса,
то такой класс не надо определять.
Существует четыре области видимости: локальная, функция, файл и класс.
Локальная: Имя, описанное в блоке ($$R.6.3), является локальным
в этом блоке и может использоваться только в нем и в блоках,
содержащихся в этом блоке и появляющихся после момента описания.
Имена формальных параметров рассматриваются, как если бы они были
описаны в самом объемлющем блоке этой функции.
Функция: Метки ($$R.6.1) можно использовать повсюду в функции,
в которой они описаны. Только метки имеют область видимости,
совпадающую с функцией.
Файл: Имя описанное вне всех блоков ($$R.6.3) и классов ($$R.9)
имеет область видимости файл и может быть использовано в единице
трансляции, в которой оно появляется после момента описания. Имена,
описанные с файловой областью видимости, называются глобальными.
Класс: Имя члена класса является локальным в своем классе и
оно может быть использовано только в функции-члене этого класса
($$R.9.3), или после операции . , применяемой к объекту данного
класса ($$R.5.2.4) или объекту производного класса($$R.10),
или после операции ->, применяемой к указателю на объект данного
класса ($$R.5.2.4) или на объект производного класса, или после
операции разрешения :: ($$R.5.1), примененной к имени данного
или производного класса. Имя, введенное с помощью операции
friend ($$R.11.4), принадлежит той же области определенности,
что и класс, содержащий описание friend. Класс, впервые
описанный в операторе return или в типе параметра, принадлежит
к глобальной области видимости.
Специальные соглашения действуют на имена, введенные при описании
параметров функции ($$R.8.2.5) и в описаниях friend ($$R.11.4).
Имя может быть скрыто явным описанием того же имени в объемлющем
блоке или классе. Скрытое имя члена класса все-таки можно
использовать, если оно предваряется именем класса, к которому
применена операция :: ($$R.4.1, $$R.9.4, $$R.10). Скрытое имя объекта,
функции, типа или элемента перечисления с файловой областью видимости
можно использовать, если оно предваряется унарной операцией ::
($$R.5.1). В дополнении к этому, имя класса ($$R.9.1) может быть
скрыто именем объекта, функции или элемента перечисления, имеющего
ту же область видимости. Если класс и объект, или функция, или
элемент перечисления описаны (в любом порядке) с одинаковым именем
в одной области видимости, то имя класса становится скрытым. Имя
класса, скрытое в локальной области видимости или в области
видимости класса именем объекта, функции или элемента перечисления,
все-таки можно использовать, если предварить его подходящей
спецификацией class, struct или union ($$R.7.1.6). Аналогично,
скрытое имя элемента перечисления можно использовать, если
предварить его спецификацией типа enum ($$R.7.1.6). В $$R.10.4
приводится сводка правил области видимости.
Моментом описания имени считается момент завершения описателя имени
($$R.8), предшествующей части инициализации (если она есть).
Например,
int x = 12;
{ int x = x; }
Здесь второе x инициализируется своим собственным (неопределенным)
значением.
Моментом описания элемента перечисления считается момент сразу
после появления его идентификатора, например:
enum { x = x };
Здесь элемент перечисления x опять инициализируется своим собственным
(неопределенным) значением.
Программа состоит из одного или нескольких файлов, связываемых вместе
($$R.2). Файл состоит из последовательности описаний.
Имя с файловой областью видимости, которое явно описано как
static, является локальным в своей единице трансляции и может
использоваться для именования объектов, функций и т.п. в других
единицах трансляции. Говорят, что такие имена имеют внутреннее
связывание. Имя с файловой областью видимости, которое явно описано
со спецификацией inline, является локальным в своей единице
трансляции. Имя с файловой областью видимости, которое явно описано
со спецификацией const и не описано явно как extern, считается
локальным в своей единице трансляции. То же верно для имени класса,
которое не использовалось в нелокальных для данной единицы
трансляции описаниях объекта, функции или класса, и который не
имеет статических членов ($$R.9.4), не имеет функций-членов, кроме
подстановок ($$R.9.3.2). Всякое описание некоторого имени с
файловой областью видимости, которое не описано одним из перечисленных
способов так, чтобы иметь внутреннее связывание, в многофайловой
программе обозначает один и тот же объект ($$R.3.7), функцию
($$R.8.2.5) или класс ($$R.9). Такие имена называются внешними или
говорят, что они имеют внешнее связывание. В частности, поскольку
нельзя описать имя класса как static, всякое употребление имени
некоторого класса с файловой областью видимости, который (класс)
использовался для описания объекта или функции с внешним связыванием,
или же который имеет статический член или функцию-член,
не являющуюся подстановкой, будет обозначать один и тот же класс.
Имена определяемых типов (typedef $$R.7.13), элементы перечисления
($$R.7.2) или имена шаблонов типа ($$R.14) не имеют внешнего
связывания.
Статические члены класса ($$R.9.4) допускают внешнее связывание.
Функции-члены, не являющиеся подстановкой, допускают внешнее
связывание. Функции-члены, являющиеся подстановкой, должны иметь
в точности одно определение в программе.
Локальные имена ($$R.3.2), явно описанные со спецификацией
extern, имеют внешнее связывание, если только они уже не были
описаны как static ($$R.7.1.1).
Типы, используемые во всех описаниях некоторого внешнего имени,
должны совпадать, за исключением использования имен определяемых
типов ($$R.7.1.3) и указания границ массивов ($$R.8.2.4).
Должно быть в точности одно определение для каждой функции, объекта,
класса и элемента перечисления, используемых в программе. Однако,
если функция никогда не вызывается и ее адрес никогда не используется,
ее не нужно определять. Аналогично, если имя класса используется
только таким образом, что не требуется знать определение класса,
то класс не нужно определять.
Область видимости функции может быть только файл или класс.
С помощью спецификации связывания можно добиться связывания с
описаниями на другом языке ($$R.7.4).
Программа должна содержать функцию с именем main(). Ей приписывается
роль начала программы. Эта функция не является предопределенной
для транслятора, она не может быть перегружена, а ее тип зависит
от реализации. Предполагается, что любая реализация должна
допускать два приведенных ниже определения и что можно добавлять
после argv любые параметры. Функция main может определяться так
int main() { /* ... */ }
или
int main(int argc, char* argv[]) { /* ... */ }
В последнем определении argc задает число параметров, передаваемых
программе окружением, в котором она выполняется. Если argc не
равно нулю, параметры должны передаваться как строки, завершающиеся
символом '\0', с помощью argv[0] до argv[argc-1], причем
argv[0] должно быть именем, под которым программа была запущена,
или "". Должно гарантироваться, что argv[argc]==0.
Функция main() не должна вызываться в программе. Связывание
main() ($$R.3.3) зависит от реализации. Нельзя получать адрес
main() и не следует описывать ее как inline или static.
Вызов функции
void exit(int);
описанной в <stdlib.h>, завершает программу. Значение параметра
передается окружению программы в качестве результата программы.
Инициализация нелокальных статических объектов ($$R.3.5)
единицы трансляции происходит прежде первого обращения к функции
или объекту, определенному в этой единице трансляции. Эта
инициализация ($$R.8.4, $$R.9.4, &&R.12.1, $$R.12.6.1) может
быть проведена перед выполнением первого оператора main() или
отложена до любого момента, предшествующего первому использованию
функции или объекта, определенных в данной единице трансляции.
Все статические объекты по умолчанию инициализируются нулем ($$R.8.4)
прежде любой динамической (во времени выполнения программы)
инициализации. Больше никаких требований на порядок инициализации
объектов из различных единиц трансляции не налагается. Инициализация
локальных и статических объектов описана в $$R.8.4.
Деструкторы ($$R.12.4) для инициализированных статических
объектов вызываются при возврате из main() или при вызове exit().
Уничтожение происходит в обратном порядке по сравнению с
инициализацией. С помощью функции atexit() из <stdlib.h> можно
указать функцию, которую нужно вызывать при выходе из программы.
Если было обращение к функции atexit(), объекты, инициализированные
до вызова atexit(), не должны уничтожаться до тех пор, пока не
произойдет вызов функции, указанной в atexit(). Если реализация С++
сосуществует с реализацией С, все действия, которые должны были
произойти после вызова функции, заданной в atexit(), происходят
только после вызова всех деструкторов.
Вызов функции
void abort();
описанной в <stdlib.h>, завершает программу без выполнения
деструкторов статических объектов и без вызова функций, заданных
в atexit().
Существует два описываемых класса памяти: автоматический и статический.
Автоматические объекты становятся локальными при передаче
управления в каждый блок.
Статические объекты существуют и сохраняют свое значение во все
время выполнения программы.
Автоматические объекты инициализируются ($$R.12.1) всякий раз,
когда управление переходит в блок, где они определены и уничтожаются
($$R.12.4) по выходе из этого блока ($$R.6.7).
Поименованный автоматический объект не должен быть уничтожен
до окончания его блока, точно так же, как не может быть исключен
поименованный автоматический объект класса, имеющего конструктор
или деструктор с побочным эффектом, даже если кажется, что этот
объект не используется.
Аналогично, глобальный объект класса с конструктором или
деструктором, имеющими побочный эффект, не может быть исключен,
даже если кажется, что он не используется.
Статические объекты инициализируются и уничтожаются в
соответствии с описанием в $$R.3.4 и $$R.6.7. С некоторыми объектами
не связано никакого имени, см. $$R.5.3.3 и $$R.12.2. Все глобальные
объекты имеют класс памяти статический. Локальным объектам и членам
класса можно предать класс памяти статический с помощью явного
использования спецификации класса памяти static ($$R.7.1.1).
Существуют два вида типов: основные и производные.
Существует несколько основных типов. В стандартном заголовочном
файле <limits.h> задаются в зависимости от реализации минимальные и
максимальные значения каждого типа.
Объекты, описанные как символы (char), могут хранить любой
элемент из базового набора символов данной машины. Если символ
этого набора хранится в символьной переменной, то ее значение
равно целому значению кода этого символа. Символы могут явно
описываться как unsigned или signed. Обычный char, signed char и
unsigned char являются тремя различными типами. Для всех этих
трех типов требуется одинаковый объем памяти.
С помощью описаний short int, int и long int можно определить
целые трех различных размеров. Для длинных целых требуется памяти
не меньше чем для коротких целых, но в реализации или короткие
целые, или длинные целые, или и те и другие могут оказаться
эквивалентными обычным целым. Обычные целые имеют размер,
определяемый системой команд, размеры других целых определяются
конкретными потребностями.
Для каждого из типов signed char, short, int и long существует
соответствующий беззнаковый тип, который занимает тот же объем
памяти и удовлетворяет тем же требованиям выравнивания.
Требование выравнивание - это ограничение на значение указателя
на данный объект, которое накладывает реализация ($$R.5.4).
Беззнаковые целые, описанные как unsigned, подчиняются законом
арифметики по модулю 2@n, где n число битов, используемое для
представления значения. Отсюда следует, что в арифметике беззнаковых
не возникает переполнения.
Существует три типа с плавающей точкой: float, double и long double.
Тип double гарантирует не меньшую точность представления, чем
float, а тип long double гарантирует точность не меньше, чем у
double. Характеристики основных типов с плавающей точкой определяются
в соответствии с реализацией в стандартном заголовочном файле
<float.h>.
Типы char, int любых размеров и тип перечисления ($$R.7.2)
называются целочисленными типами. Целочисленные типы вместе с
типами с плавающей точкой образуют арифметические типы.
Тип void задает пустое множество значений. Он используется для
обозначения типа функций, которые не возвращают результат. Нельзя
описывать объекты с типом void. Любое выражение можно явно
преобразовать к типу void ($$R.5.4), получившееся выражение можно
использовать только как выражение-оператор ($$R.6.2), как