7. Выражения
Приоритет операций в выраженях такой же, как и порядок
главных подразделов в этом разделе, наибольший приоритет у
первого. Так например, выражения, о которых говорится как об
операндах операции + (#7.4) - это те выражения, которые опре-
делены в ##7.1-7.4. Внутри каждого подраздела операции имеют
одинаковый приоритет. В каждом подразделе для рассматриваемых
в нем операций определяется их левая или правая ассоциатив-
ность (порядок обработки операндов). Приоритет и ассоциатив-
ность всех операций собран вместе в описании грамматики в
#14.
побочные эффекты. Порядок возникновения
побочных эффектов неопределен. Выражения, включающие в себя
коммутативные и асссоциативные операции (*, +, &, !, ^), мо-
гут быть реорганизованы произвольным образом, даже при нали-
чии скобок; для задания определенного порядка вычисления вы-
ражения необходимо использовать явную временную переменную.
Обработка переполнения и контроль деления при вычислении
выражения машинно зависимы. В большинстве существующих реали-
заций С++ переполнение целого игнорируется; обработка деления
на 0 и всех исключительных ситуаций с числами с плавающей
точкой различаются от машины к машине и обычно могут регули-
роваться библиотечными функциями.
Кроме стандартного значения, описанного в #7.2-7.15,
операции могут быть перегружены*, то есть, могут быть заданы
их значения для случая их применения к типам, определяемым
пользователем, см. #7.16.
--------------------
* Этот термин применяется для описания использования в
языке одной и той же лексемы для обозначения различных проце-
дур; вид процедуры выбирается компилятором на основании до-
полнительной информации в виде числа и типа аргументов и т.п.
(прим.перев.)
7.1 Основные Выражения
Основные выражения, включающие в себя . , -> , индекси-
рование и вызовы функций, группируются слева направо.
список_выражений:
выражение
список_выражений , выражение
id:
идентификатор
имя_функции_операции
typedef-имя :: идентификатор
typedef-имя :: имя_функции_операции
первичное_выражение:
id
:: идентификатор
константа
строка
this
( выражение )
первичное_выражение [ выражение ]
первичное_выражение ( список_выражений opt )
первичное_выражение . id
первичное_выражение -> id
Идентификатор есть первичное выражение, причем соответс-
твенно описанное (#8). Имя_функции_операции есть идентифика-
тор со специальным значением, см. #7.16 и #8.5.1.
скрыт (#4.1).
Typedef-имя (#8.8) , за которым следует ::, после чего
следует идентификатор, является первичным выражением. Typedef
-имя должно обозначать класс (#8.5), и идентификатор должен
обозначать член этого класса. Его тип специфицируется описа-
нием идентификатора. Typedef-имя может быть скрыто именем,
которое не является именем типа. В этом случае typedef-имя
все равно может быть найдено и его можно использовать.
Константа является первичным выражением. Ее тип должен
быть int, long или double в зависимости от ее формы.
Строка является первичным выражением. Ее тип - "массив
символов". Обычно он сразу же преобразуется в указатель на ее
первый символ (#6.7).
Ключевое слово this является локальной переменной в теле
функции члена (см. #8.5) . Оно является указателем на объект,
для которого функция была вызвана.
Выражение, заключенное в круглые скобки, является пер-
вичным выражением, чей тип и значение те же, что и у незаклю-
ченного в скобки выражения. Наличие скобок не влияет на то,
является выражение lvalue или нет.
Первичное выражение, за которым следует выражение в
квадратных скобках, является первичным выражением. Интуитив-
ный смысл - индекс. Обычно первичное выражение имеет тип
"указатель на ...", индексирующее выражение имеет тип int и
тип результата есть "...". Выражение Е1[Е2] идентично (по оп-
ределению) выражению *((E1)+(E2)). Все тонкие места, необхо-
димые для понимания этой записи, содержатся в этом разделе
вместе с обсуждением в ## 7.1, 7.2 и 7.4, соответственно,
идентификаторов, * и + ; ниже, в #8.4.2 приводятся следствия
из этого.
Вызов функции является первичным выражением, за которым
следуют скобки, содержащие список (возможно, пустой) разде-
ленных запятыми выражений, составляющих фактические параметры
для функции. Первичное выражение должно иметь тип "функция,
возвращающая ..." или "указатель на функцию, возвращающую
...", и результат вызова функции имеет тип "...".
Каждый формальный параметр инициализируется фактическим
параметром (#8.6). Выполняются стандартные (#6.6-8) и опреде-
ляемые пользователем преобразования (#8.5.6). Функция может
изменять значения своих формальных параметров, но эти измене-
ния не могут повлиять на значения фактических параметров за
исключением случая, когда формальный параметр имеет ссылочный
тип.
Функция может быть описана как получающая меньше или
больше параметров, чем специфицировано в описании функции
(#8.4). Каждый фактический параметр типа float, для которого
нет формального параметра, преобразуются к типу double; и,
как обычно, имена массивов преобразуются к указателям. Поря-
док вычисления параметров не определен языком; имейте в виду
различия между компиляторами.
Допустимы рекурсивные вызовы любых функций.
Первичное выражение, после которого стоит точка, за ко-
торой следует идентификатор (или идентификатор, уточненный
typedef-именем с помощью операции ::) является выражением.
Первое выражение должно быть объектом класса, а идентификатор
должен именовать член этого класса. Значением является имено-
ванный член объекта, и оно является адресным, если первое вы-
ражение является адресным. Следует отметить, что "классовые
объекты" могут быть структурами (#8.5.12) или объединениями
(#8.5.13).
Первичное выражение, после которого стоит стрелка ( ->
), за которой следует идентификатор (или идентификатор, уточ-
ненный typedef-именем с помощью операции ::) является выраже-
нием. Первое выражение должно быть указателем на объект клас-
са, а идентификатор должен именовать член этого класса.
Значение является адресом, ссылающимся на именованный член
класса, на который указывает указательное выражение. Так, вы-
ражение E1->MOS есть то же, что и (*E1).MOS. Классы обсужда-
ются в #8.5.
Если первичное выражение дает значение типа "указатель
на ..." (см. #8.4 and #8.6.3), значением выражения был объ-
ект, обозначаемый ссылкой. Ссылку можно считать именем объек-
та, см. #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).
Операнд префиксного -- уменьшается аналогично действию
префиксной операции ++.
Значение, получаемое при использовании постфиксного ++,
есть значение операнда. Операнд должен быть адресным. После
того, как результат отмечен, объект увеличивается так же, как
и в префиксной операции ++. Тип результата тот же, что и тип
операнда.
Значение, получаемое при использовании постфиксной --,
есть значение операнда. Операнд должен быть адресным. После
того, как результат отмечен, объект увеличивается так же, как
и в префиксной операции ++. Тип результата тот же, что и тип
операнда.
7.2.2 sizeof
Операция sizeof дает размер операнда в байтах. (Байт не
определяется языком иначе, чем через значение sizeof. Однако,
во всех существующих реализациях байт есть пространтсво, не-
обходимое для хранения char.) При применении к массиву ре-
зультатом является полное количество байтов в массиве. Размер
определяется из описаний объектов, входящих в выражение. Се-
мантически это выражение является беззнаковой константой и
может быть использовано в любом месте, где требуется констан-
та.
Операцию sizeof можно также применять к заключенному в
скобки имени типа. В этом случае она дает размер, в байтах,
объекта указанного типа.
7.2.3 Явное Преобразование Типа
конструктором #8.5.5) влечет преобразование
значения выражения в названный тип. Чтобы записать преобразо-
вание в тип, не имеющий простого имени, имя_типа (#8.7) долж-
но быть заключено в скобки. Если имя типа заключено в скобки,
выражение заключать в скобки необязательно. Такая запись на-
зывается приведением к типу.
Указатель может быть явно преобразован к любому из цело-
численных типов, достаточно по величине для его хранения. То,
какой из int и long требуется, является машинно зависимым.
Отобразующая функция также является машинно зависимой, но
предполагается, что она не содержит сюрпризов для того, кто
знает структуру адресации в машине. Подробности для некоторых
конкретных машин были приведены в #2.6.
Объект целочисленного типа может быть явно преобразован
в указатель. Отображающая функция всегда превращает целое,
полученное из указателя, обратно в тот же указатель, но в ос-
тальных случаях является машинно зависимой.
Указатель на один тип может быть явно преобразован в
указатель на другой тип. Использование полученного в резуль-
тате указателя может привести к исключительной ситуации адре-
сации, если исходный указатель не указывает на объект, соот-
ветствующим образом выравненный в памяти. Гарантируется, что
указатель на объект данного размера может быть преобразован в
указатель на объект меньшего размера и обратно без изменений.
Различные машины могут различаться по числу бит в указателях
и требованиям к выравниванию объектов. Составные объекты вы-
равниваются по самой строгой границе, требуемой каким-либо из
его составляющих.
Объект может преобразовываться в объект класса только
если был описан соответствующий конструктор или операция пре-
образования (#8.5.6).
Объект может явно преобразовываться в ссылочный тип &x,
если указатель на этот объект может явно преобразовываться в
x*.
7.2.4 Свободная Память
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 Мультипликативные Операции
Мультипликативные операции *, / и % группируют слева
направо. Выполняются обычные арифметические преобразования.
мультипликативное_выражение:
выражение * выражение
выражение / выражение
выражение % выражение
Бинарная операция * определяет умножение. Операция * ас-
социативна и выражения с несколькими умножениями на одном
уровне могут быть реорганизованы компилятором.
Бинарная операция / определяет деление. При делении по-
ложительных целых округление осуществляется в сторону 0, но
если какой-либо из операндов отрицателен, то форма округления
является машинно зависимой. На всех машинах, охватываемых
данным руководством, остаток имеет тот же знак, что и дели-
мое. Всегда истиинно, что (a/b)*b + a%b равно a (если b не
0).
Бинарная операция % дает остаток от деления первого вы-
ражения на второе. Выполняются обычные арифметические преоб-
разования. Операнды не должны быть числами с плавающей точ-
кой.
7.4 Аддитивные Операции
Аддитивные операции + и - группируют слева направо.
Выполняюься обычные арифметические преобразования. Каждая
операция имеет некоторые дополнительные возможности, связан-
ные с типами.
аддитивное_выражение:
выражение + выражение
выражение - выражение
Результатом операции + является сумма операндов. Можно
суммировать указатель на объект массива и значение целого ти-
па. Последнее во всех случаях преобразуется к смещению адреса
с помощью умножения его на длину объекта, на который указыва-
ет указатель. Результатом является указатель того же типа,
что и исходный указатель, уазывающий на другой объект того же
массива и соответствующим образом смещенный от первоначально-
го объекта. Так, если p есть указатель на объект массива, то
выражение p+1 есть указатель на следующий объект массива.
Никакие другие комбинации типов для указателей не допус-
тимы.
Операция + ассоциативна и выражение с несколькими умно-
жениями на одном уровне может быть реорганизовано компилято-
ром.
применяются те же преобразования, что и к
сложению.
Если вычитаются указатели на объекты одного типа, то ре-
зультат преобразуется (посредством деления на длину объекта)
к целому, представляющему собой число объектов, разделяющих
объекты, указанные указателями. В засисимости от машины ре-
зультирующее целое может быть или типа int, или типа long,
см. #2.6. Вообще говоря, это преобразование будет давать не-
определенный результат кроме тех случаев, когда указатели
указывают на объекты одного массива, поскольку указатели, да-
же на объекты одинакового типа, не обязательно различаются на
величину, кратную длине объекта.
7.5 Операции Сдвига
Операции сдвига << и >> группируют слева направо. Обе
выполняют одно обычное арифметическое преобразование над сво-
ими операндами, каждый из которых должен быть целым. В этом
случае правый операнд преобразуется к типу int; тип результа-
та совпадает с типом левого операнда. Результат неопределен,
если правый операнд отрицателен или больше или равен длине
объекта в битах.
сдвиговое_выражение:
выражение << выражение
выражение >> выражение
Значением Е1 << Е2 является Е1 (рассматриваемое как би-
товое представление), сдвинутое влево на Е2 битов; освободив-
шиеся биты заполняются нулями. Значением Е1 >> Е2 является Е1
, сдвинутое вправо на Е2 битовых позиций. Гарантируется, что
сдвиг вправо является логическим (заполнение нулями), если Е1
является unsigned; в противном случае он может быть арифмети-
чевким (заполнение копией знакового бита).
7.6 Операции Отношения
Операции отношения (сравнения) группируют слева направо,
но этот факт не очень-то полезен: a < b < c не означает то,
чем кажется.
выражение_отношения:
выражение < выражение
выражение > выражение
выражение <= выражение
выражение >= выражение
Операции < (меньше чем), > (больше чем), <= и > от относительного положения объектов, на которые указыва-
ют указатели, в адресном пространстве. Сравнение указателей
переносимо только если указатели указывают на объекты одного
массива.
7.7 Операции Равенства
выражение_равенства:
выражение == выражение
выражение != выражение
<b == c<d
есть 1 всегда, когда a<b и c<d имеют одинаковое истинностное
значение.)
Указатель может сравниваться с 0.
7.8 Операция Побитовое И
И-выражение:
выражение & выражение
& ассоциативна, и выражения, содержащие &, мо-
гут реорганизовываться. Выполняются обычные арифметические
преобразования; результатом является побитовая функция И опе-
рандов. Операция применяется только к целым операндам.
7.9 Операция Побитовое Исключающее ИЛИ
исключающее_ИЛИ_выражение:
выражение ^ выражение
Операция применяется только к целым
операндам.
7.10 Операция Побитовое Включающее ИЛИ
включающее_ИЛИ_выражение:
выражение ! выражение
Операция применяется только к целым
операндам.
7.11 Операция Логическое И
логическое_И_выражение:
выражение && выражение
Операция && группирует слева направо. Она возвращает 1,
если оба операнда ненулевые, и 0 в противном случае. В проти-
воположность операции & операция && гарантирует вычисление
слева направо; более того, второй операнд не вычисляется, ес-
ли первый операнд есть 0.
Операнды не обязаны иметь один и тот же тип, но каждый
из них должен иметь один из основных типов или быть указате-
лем. Результат всегда имеет тип int.
7.12 Операция Логическое ИЛИ
логическое_ИЛИ_выражение:
выражение !! выражение
Операция !! группирует слева направо. Она возвращает 1,
если хотя бы один из ее операндов ненуелвой, и 0 в противном
случае. В противоположность операции ! операция !! гарантиру-
ет вычисление слева направо; более того, второй операнд не
вычисляется, если первый операнд не есть 0.
Операнды не обязаны иметь один и тот же тип, но каждый
из них должен иметь один из основных типов или быть указате-
лем. Результат всегда имеет тип int.
7.13 Условная Операция
условное_выражение:
выражение ? выражение : выражение
Если это возможно, то выполняются обычные
арифметические преобразования для приведения второго и треть-
его выражения к общему типу. Если это возможно, то выполняют-
ся преобразования указателей для приведения второго и треть-
его выражения к общему типу. Вычисляется только одно из
второго и третьего выражений.
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.
7.16 Перегруженные Операции
смысл операций при применении их к
неклассовым объектам. Предопределенный смысл операций = и &
(унарной) при применении их к объектам классов может быть из-
менен.
присваивание, в случае применения к основным
типам требуют, чтобы операнд был 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.operator
@(y) или operator@(x,y).
7.16.3 Особые Операции
Вызов функции
первичное_выражение ( список_выражений opt )
и индексирование
первичное_выражение [ выражение ]
считаются бинарными операциями. Именами определяющей
функции являются соответсвенно operator() и operator[]. Обра-
щение x(arg) интерпретируется как x.operator()(arg) для клас-
сового объекта x. Индексирование x[y] интерпретируется как x.
operator[](y).
[Назад] [Содержание] [Вперед]
| Главная |