Жанр: Учеба
Язык С++ с комментариями
...е выражение дает значение типа "указатель на ..."
(см. #8.4 and #8.6.3), значением выражения был объект,
- стр 266 -
обозначаемый ссылкой. Ссылку можно считать именем объекта; см.
#8.6.3.
7.2 Унарные операции
Выражения с унарными операциями группируют справа налево:
унарное_выражение:
унарная_операция выражение
выражение ++
выражение --
sizeof выражение
sizeof ( имя_типа )
( имя_типа ) выражение
простое_имя_типа ( список_выражений )
new имя_типа инициализатор opt
new ( имя_типа )
delete выражение
delete [ выражение ] выражение
унарная_операция: одна из
* & - ! ~ ++ --
Унарная операция * означает косвенное обращение: выражение должно
быть указателем и результатом будет lvalue, ссылающееся на объект,
на который указывает выражение. Если выражение имеет тип "указатель
на ...", то тип результата есть "...".
Результатом унарной операции & является указатель на объект, на
который ссылается операнд. Операнд должен быть lvalue. Если
выражение имеет тип "...", то тип результата есть "указатель на
...".
Результатом унарной операции + является значение ее операнда
после выполнения обычных арифметических преобразований. Операнд
должен быть арифметического типа.
Результатом унарной операции - является отрицательное значение ее
операнда. Операнд должен иметь целый тип. Выполняются обычные
арифметические преобразования. Отрицательое значение беззнаковой
величины вычислятся посредством вычитания ее значения из 2n, где n
-число битов в целом типа int.
Результатом операции логического отрицания ! является 1, если
значение операнда 0, и 0, если значение операнда не 0. Результат
имеет тип int. Применима к любому арифметическому типу или к
указателям.
Операция ~ дает дополнение значения операнда до единицы.
Выполняются обычные арифметические преобразования. Операнд должен
иметь интегральный тип.
7.2.1 Увеличение и Уменьшение
Операнд префиксного ++ получает приращение. Операнд должен быть
адресным . Значением является новое значение операнда, но оно не
адресное. Выражение ++x эквивалентно x+=1. По поводу данных о
преобразованиях см. обсуждение операций сложения (#7.4) и
присваивания (#7.14).
Операнд префиксного — уменьшается аналогично действию префиксной
операции ++.
- стр 267 -
Значение, получаемое при использовании постфиксного ++, есть
значение операнда. Операнд должен быть адресным. После того, как
результат отмечен, объект увеличивается так же, как и в префиксной
операции ++. Тип результата тот же, что и тип операнда.
Значение, получаемое при использовании постфиксной
--, есть значение операнда. Операнд должен быть адресным. После
того, как результат отмечен, объект увеличивается так же, как и в
префиксной операции ++. Тип результата тот же, что и тип операнда.
7.2.2 Sizeof
Операция sizeof дает размер операнда в байтах. (Байт не
определяется языком иначе, чем через значение sizeof. Однако, во
всех существующих реализациях байт есть пространтсво, необходимое
для хранения char.) При применении к массиву результатом является
полное количество байтов в массиве. Размер определяется из описаний
объектов, входящих в выражение. Семантически это выражение является
беззнаковой константой и может быть использовано в любом месте, где
требуется константа.
Операцию sizeof можно также применять к заключенному в скобки
имени типа. В этом случае она дает размер, в байтах, объекта
указанного типа.
7.2.3 Явное Преобразование Типа
Простое_имя_типа (#8.2), возможно, заключенное в скобки, за
которым идет заключенное в скобки выражение (или список_выражений,
если тип является классом с соответствующим образом описанным
конструктором #8.5.5) влечет преобразование значения выражения в
названный тип. Чтобы записать преобразование в тип, не имеющий
простого имени, имя_типа (#8.7) должно быть заключено в скобки.
Если имя типа заключено в скобки, выражение заключать в скобки
необязательно. Такая запись называется приведением к типу.
Указатель может быть явно преобразован к любому из интегральных
типов, достаточно по величине для его хранения. То, какой из int и
long требуется, является машинно зависимым. Отобразующая функция
также является машинно зависимой, но предполагается, что она не
содержит сюрпризов для того, кто знает структуру адресации в
машине. Подробности для некоторых конкретных машин были приведены в
#2.6.
Объект интегрального типа может быть явно преобразован в
указатель. Отображающая функция всегда превращает целое, полученное
из указателя, обратно в тот же указатель, но в остальных случаях
является машинно зависимой.
Указатель на один тип может быть явно преобразован в указатель на
другой тип. Использование полученного в результате указателя может
привести к исключительной ситуации адресации, если исходный
указатель не указывает на объект, соответствующим образом
выравненный в памяти. Гарантируется, что указатель на объект
данного размера может быть преобразован в указатель на объект
меньшего размера и обратно без изменений. Различные машины могут
различаться по числу бит в указателях и требованиям к выравниванию
объектов. Составные объекты выравниваются по самой строгой границе,
требуемой каким-либо из его составляющих.
- стр 268 -
Объект может преобразовываться в объект класса только если был
описан соответствующий конструктор или операция преобразования
(#8.5.6).
Объект может явно преобразовываться в ссылочный тип &X, если
указатель на этот объект может явно преобразовываться в X*.
7.2.4 Свободная Память
Операция new создает объект типа имя_типа (см. #8.7), к которому
он применен. Время жизни объекта, созданного с помощью new, не
ограничено областью видимости, в которой он создан. Операция new
возвращает указатель на созданный ей объект. Когда объект является
массивом, возвращается указаетль на его первый элемент. Например, и
new int и new int[10] возвращают int*. Для объектов некоторых
классов надо предоставлять инициализатор (#8.6.2). Операция new
(#7.2) для получения памяти вызывает функцию
void* operator new (long);
Параметр задает требуемое число байтов. Память будет
инициализирована. Если operator new() не может найти требуемое
количество памяти, то она возвращает ноль.
Операция delete уничтожает объект, созданный операцией new. Ее
результат является void. Операнд delete должен быть указателем,
возвращенным new. Результат применения delete к указателю, который
не был получен с помощью операции new. Однако уничтожение с помощью
delete указателя со значением ноль безвредно.
Чтобы освободить указанную память, операция delete вызывает
функцию
void operator delete (void*);
В форме
delete [ выражение ] выражение
второй параметр указывает на вектор, а первое выражение задает
число элементов этого вектора. Задание числа элементов является
избыточным за исключением случаев уничтожения векторов некоторых
классов; см. #8.5.8.
7.3 Мультипликативные операции
Мультипликативные операции *, / и % группируют слева направо.
Выполняются обычные арифметические преобразования.
мультипликативное_выражение:
выражение * выражение
выражение / выражение
выражение % выражение
Бинарная операция * определяет умножение. Операция * ассоциативна
и выражения с несколькими умножениями на одном уровне могут быть
реорганизованы компилятором.
- стр 269 -
Бинарная операция / определяет деление. При делении положительных
целых округление осуществляется в сторону 0, но если какой-либо из
операндов отрицателен, то форма округления является машинно
зависимой. На всех машинах, охватываемых данным руководством,
остаток имеет тот же знак, что и делимое. Всегда истиинно, что
(a/b)*b + a%b равно a (если b не 0).
Бинарная операция % дает остаток от деления первого выражения на
второе. Выполняются обычные арифметические преобразования. Операнды
не должны быть числами с плавающей точкой.
7.4 Аддитивные операции
Аддитивные операции + и - группируют слева направо. Выполняюься
обычные арифметические преобразования. Каждая операция имеет
некоторые дополнительные возможности, связанные с типами.
аддитивное_выражение:
выражение + выражение
выражение - выражение
Результатом операции + является сумма операндов. Можно
суммировать указатель на объект массива и значение целого типа.
Последнее во всех случаях преобразуется к смещению адреса с помощью
умножения его на длину объекта, на который указывает указатель.
Результатом является указатель того же типа, что и исходный
указатель, уазывающий на другой объект того же массива и
соответствующим образом смещенный от первоначального объекта. Так,
если P есть указатель на объект массива, то выражение P+1 есть
указатель на следующий объект массива.
Никакие другие комбинации типов для указателей не допустимы.
Операция + ассоциативна и выражение с несколькими умножениями на
одном уровне может быть реорганизовано компилятором.
Результатом операции - является разность операндов. Выполняюься
обычные арифметические преобразования. Кроме того, значение любого
целого типа может вычитаться из указателя, в этом случае
применяются те же преобразования, что и к сложению.
Если вычитаются указатели на объекты одного типа, то результат
преобразуется (посредством деления на длину объекта) к целому,
представляющему собой число объектов, разделяющих объекты,
указанные указателями. В засисимости от машины результирующее целое
может быть или типа int, или типа long; см. #2.6. Вообще говоря,
это преобразование будет давать неопределенный результат кроме тех
случаев, когда указатели указывают на объекты одного массива,
поскольку указатели, даже на объекты одинакового типа, не
обязательно различаются на величину, кратную длине объекта.
7.5 Операции сдвига
Операции сдвига "" и "" группируют слева направо. Обе выполняют
одно обычное арифметическое преобразование над своими операндами,
каждый из которых должен быть целым. В этом случае правый операнд
преобразуется к типу int; тип результата совпадает с типом левого
операнда. Результат неопределен, если правый операнд отрицателен
или больше или равен длине объекта в битах.
- стр 270 -
сдвиговое_выражение:
выражение "" выражение
выражение "" выражение
Значением Е1 "" Е2 является Е1 (рассматриваемое как битовое
представление), сдвинутое влево на Е2 битов; освободившиеся биты
заполняются нулями. Значением Е1 "" Е2 является Е1 , сдвинутое
вправо на Е2 битовых позиций. Гарантируется, что сдвиг вправо
является логическим (заполнение нулями), если Е1 является unsigned;
в противном случае он может быть арифметичевким (заполнение копией
знакового бита).
7.6 Операции отношения
Операции отношения (сравнения) группируют слева направо, но этот
факт не очень-то полезен: a " b " c не означает то, чем кажется.
выражение_отношения:
выражение " выражение
выражение " выражение
выражение "= выражение
выражение "= выражение
Операции " (меньше чем), " (больше чем), "= и "= все дают 0, если
заданное соотношение ложно, и 1, если оно истинно. Тип результата
int. Выполняются обычные арифметические преобразования. Могут
сравниваться два указателя; результат зависит от относительного
положения объектов, на которые указывают указатели, в адресном
пространстве. Сравнение указателей переносимо только если указатели
указывают на объекты одного массива.
7.7 Операции равенства
выражение_равенства:
выражение == выражение
выражение != выражение
Операции == и != в точности аналогичны операциям сравнения за
исключением их низкого приоритета. (Так, a
7.8 Операция побитовое И
И-выражение: выражение & выражение
Операция & ассоциативна, и выражения, содержащие &, могут
реорганизовываться. Выполняются обычные арифметические
преобразования; результатом является побитовая функция И операндов.
Операция применяется только к целым операндам.
7.9 Операция побитовое исключающее ИЛИ
исключающее_ИЛИ_выражение:
выражение ^ выражение
Операция ^ ассоциативна, и выражения, содержащие ^, могут
реорганизовываться. Выполняются обычные арифметические
- стр 271 -
преобразования; результатом является побитовая функция исключающее
ИЛИ операндов. Операция применяется только к целым операндам.
7.10 Операция побитовое включающее ИЛИ
включающее_ИЛИ_выражение:
выражение | выражение
Операция | ассоциативна, и выражения, содержащие |, могут
реорганизовываться. Выполняются обычные арифметические
преобразования; результатом является побитовая функция включающее
ИЛИ операндов. Операция применяется только к целым операндам.
7.11 Операция логическое И
логическое_И_выражение:
выражение && выражение
Операция && группирует слева направо. Она возвращает 1, если оба
операнда ненулевые, и 0 в противном случае. В противоположность
операции & операция && гарантирует вычисление слева направо; более
того, второй операнд не вычисляется, если первый операнд есть 0.
Операнды не обязаны иметь один и тот же тип, но каждый из них
должен иметь один из основных типов или быть указателем. Результат
всегда имеет тип int.
7.12 Операция логическое ИЛИ
логическое_ИЛИ_выражение:
выражение || выражение
Операция || группирует слева направо. Она возвращает 1, если хотя
бы один из ее операндов ненуелвой, и 0 в противном случае. В
противоположность операции | операция || гарантирует вычисление
слева направо; более того, второй операнд не вычисляется, если
первый операнд не есть 0.
Операнды не обязаны иметь один и тот же тип, но каждый из них
должен иметь один из основных типов или быть указателем. Результат
всегда имеет тип int.
7.13 Условная операция
условное_выражение:
выражение ? выражение : выражение
Условная операция группирует слева направо. Вычисляется первое
выражение, и если оно не 0, то результатом является значение
второго выражения, в противном случае значение третьего выражения.
Если это возможно, то выполняются обычные арифметические
преобразования для приведения второго и третьего выражения к общему
типу. Если это возможно, то выполняются преобразования указателей
для приведения второго и третьего выражения к общему типу.
Вычисляется только одно из второго и третьего выражений.
- стр 272 -
7.14 Операции присваивания
Есть много операций присваивания, все группируют слева направо.
Все в качестве левого операнда требуют lvalue, и тип выражения
присваивания тот же, что и у его левого операнда. Это lvalue не
может ссылаться на константу (имя массива, имя функции или const).
Значением является значение, хранящееся в левом операнде просле
выполнения присваивания.
выражение_присваивания:
выражение операция_присваивания выражение
операция_присваивания: одна из
= += -= *= /= %= ""= ""= &= ~= |=
В простом присваивании с = значение выражения замещает собой
значение объекта, на который ссылается операнд в левой части. Если
оба операнда имеют арифметический тип, то при подготовке к
присваиванию правый операнд преобразуется к типу левого. Если
аргумент в левой части имеет указательный тип, аргумент в правой
части должен быть того же типа или типа, кторый может быть
преобразован к нему, см. #6.7. Оба операнда могут быть объектами
одного класса. Могут присваиваться объекты некоторых производных
классов; см. #8.5.3.
Присваивание объекту типа "указатель на ..." выполнит
присваивание объекту, денотируемому ссылкой.
Выполнение выражения вида E1 op= E2 можно представить себе как
эквивалентное E1 = E1 op (E2); но E1 вычисляется только один раз. В
+= и -= левый операнд может быть указателем, и в этом случае
(интегральный) правый операнд преобразуется так, как объяснялось в
#7.4; все правые операнды и не являющиеся указателями левые должны
иметь арифметический тип.
7.15 Операция запятая
запятая_выражение:
выражение , выражение
Пара выражений, разделенных запятой, вычисляется слева направо,
значение левого выражения теряется. Тип и значение результата
являются типом и значением правого операнда. Эта операция
группирует слева направо. В контексте, где запятая имеет
специальное значение, как например в списке фактических параметров
функции (#7.1) и в списке инициализаторов (#8.6), операция
запятая, как она описана в этом разделе, может появляться только в
скобках; например,
f (a,(t=3,t+2),c)
имеет три параметра, вторым из которых является значение 5.
- стр 273 -
7.16 Перегруженные операции
Большинство операций может быть перегружено, то есть, описано
так, чтобы они получали в качестве операндов объекты классов (см.
#8.5.11). Изменить приоритет операций невозможно. Невозможно
изменить смысл операций при применении их к неклассовым объектам.
Предопределенный смысл операций = и & (унарной) при применении их к
объектам классов может быть изменен.
Эквивалентность операций, применяемых к основным типам (например,
++a эквивалентно a+=1), не обязательно выполняется для операций,
применяемых к классовым типам. Некоторые операции, например,
присваивание, в случае применения к основным типам требуют, чтобы
операнд был lvalue; это не требуется для операций, описанных для
классовых типов.
7.16.1 Унарные операции
Унарная операция, префиксная или постфиксная, может быть
определена или с помощью функции члена (см. #8.5.4), не получающей
параметров, или с помощью функции друга (см. #8.5.10), получающей
один параметр, но не двумя способами одновременно. Так, для любой
унарной операции @, x@ и @x могут интерпретироваться как
x.операция@() или операция@(x). При перегрузке операций ++ и --
невозможно различить префиксное и постфиксное использование.
7.16.2 Бинарные операции
Бинарная операция может быть определена или с помощью функции
члена (см. #8.5.4), получающей один параметр, или с помощью функции
друга (см. #8.5.9), получающей два параметра, но не двумя способами
одновременно. Так, для любой бинарной операции @, x@y может быть
проинтерпретировано как x.операция@(y) или операция@(x,y).
7.16.3 Особые операции
Вызов функции
первичное_выражение ( список_выражений opt )
и индексирование
первичное_выражение [ выражение ]
считаются бинарными операциями. Именами определяющей функции
являются соответсвенно operator() и operator[]. Обращение x(arg)
интерпретируется как x.operator()(arg) для классового объекта x.
Индексирование x[y] интерпретируется как x.operator[](y).
- стр 274 -
8. ОПИСАНИЯ
Описания используются для определения интерпретации, даваемой
каждому идентификатору; они не обязательно резервируют память,
связанную с идентификатором. Описания имеют вид:
описание:
спецификаторы_описания opt список_описателей opt ;
описание_имени
asm_описание
Описатели в списке_описателей содержат идентификаторы, подлежащие
описанию. Спецификаторы_описания могут быть опущены только в
определениях внешних функций (#10) или в описаниях внешних
функций. Список описателей может быть пустым только при описании
класса (#8.5) или перечисления (#8.10), то есть, когда
спецификаторы_описания - это class_спецификатор или
enum_спецификатор. Описания имен описываются в #8.8; описания asm
описаны в #8.11.
спецификатор_описания:
sc_спецификатор
спецификатор_типа
фнк_спецификатор
friend
typedef
спецификаторы_описания:
спецификатор_описания спецификатор_описания opt
Список должен быть внутренне непротиворечив в описываемом ниже
смысле.
8.1 Спецификаторы класса памяти
Спецификаторы "класса памяти" (sc-спецификатор) это:
sc-спецификатор:
auto
static
extern
register
Описания, использующие спецификаторы auto, static и register
также служат определениями тем, что они вызывают резервирование
соответствующего объема памяти. Если описание extern не является
определением (#4.2), то где-то еще должно быть определение для
данных идентификаторов.
Описание register лучше всего представить как описание auto
(автоматический) с подсказкой компилятору, что описанные переменные
усиленно используются. Подсказка может быть проигнорирована. К ним
не может применяться операция получения адреса &.
Спецификаторы auto или register могут применяться только к
именам, описанным в блоке, или к формальным параметрам. Внутри
- стр 275 -
блока не может быть описаний ни статических функций, ни статических
формальных параметров.
В описании может быть задан максимум один sc_спецификатор. Если в
описании отсутсвует sc_спецификатор, то класс памяти принимается
автоматическим внутри функции и статическим вне. Исключение:
функции не могут быть автоматическими.
Спецификаторы static и extern могут использоваться только для
имен объектов и функций.
Некоторые спецификаторы могут использоваться только в описаниях
функций:
фнк-спецификатор:
overload
inline
virtual
Спецификатор перегрузки overload делает возможным использование
одного имени для обозначения нескольких функций; см. #8.9.
Спецификатор inline является только подсказкой компилятору, не
влияет на смысл программы и может быть проигнорирован. Он
используется, чтобы указать на то, что при вызове функции inlineподстановка
тела функции предпочтительнее обычной реализацци вызова
функции. Функция (#8.5.2 и #8.5.10), определенная внутри описания
класса, является inline по умолчанию.
Спецификатор virtual может использоваться только в описаниях
членов класса; см. #8.5.4.
Спецификатор friend используется для отмены правил скрытия имени
для членов класса и может использоваться только внутри описаний
классов; см. #8.5.9.
С помощью спецификатора typedef вводится имя для типа; см. #8.8.
8.2 Спецификаторы Типа
Спецификаторами типов (спецификатор_типа) являются:
спецификатор_типа:
простое_имя_типа
class_спецификатор
enum-спецификатор
сложный_спецификатор_типа
const
Слово const можно добавлять к любому допустимому
спецификатору_типа. В остальных случаях в описании может быть дано
не более одного спецификатора_типа. Объект типа const не является
lvalue. Если в описании опущен спецификатор типа, он принимается
int.
- стр 276 -
простое_имя_типа:
char
short
int
long
unsigned
float
double
const
void
Слова long, short и unsigned можно рассматривать как
прилагательные. Они могут применяться к типу int; unsigned может
также применяться к типам char, short и long.
Спецификаторы класса и перечисления обсуждаются в #8.5 и #8.10
соответственно.
сложный_спецификатор_типа:
ключ typedef-имя
ключ идентификатор
ключ:
class
struct
union
enum
Сложный спецификатор типа можно использовать для ссылки на имя
класса или перечисления там, где имя может быть скрыто локальным
именем. Например:
class x { ... };
void f(int x)
{
class x a;
// ...
}
Если имя класса или перечисления ранее описано не было,
сложный_спецификатор_типа работает как описание_имени; см. #8.8.
8.3 Описатели
Список_описателей, появляющийся в описании, есть разделенная
запятыми последовательность описателей, каждый из которых может
иметь инициализатор.
список_описателей:
иниц_описатель
иниц_описатель , список_описателей
- стр 277 -
иниц_описатель:
описатель инициализатор opt
Инициализаторы обсуждаются в #8.6. Спецификатор в описании
указывает тип и класс памяти объектов, к которым относятся
описатели. Описатели имеют синтаксис:
описатель:
оп_имя
( описатель )
* const opt описатель
& const opt описатель
описатель ( список_описаний_параметров )
описатель [ константное_выражение opt ]
оп-имя:
простое_оп_имя
typedef-имя :: простое_оп_имя
простое_оп_имя:
идентификатор
typedef-имя
~ typedef-имя
имя_функции_операции
имя_функции_преобразования
Группировка та же, что и в выражениях.
8.4 Смысл описателей
Каждый описатель считается утверждением того, что если в
выражении возникает конструкция, имеющаяя ту же форму, что и
описатель, то она дает объект указанного типа и класса памяти.
Каждый описатель содержит ровно одно оп_имя; оно определяет
описываемый идентификатор. За исключеним
...Закладка в соц.сетях