6. Преобразования
   Определенные операции могут в зависимости от их операдов вызывать преобразование значения операнда от одного типа к другому. В этой части объясняется, каков ожидаемый резултат таких преобразований. В #6.6 содержится краткое описание преобразований, требуемых наиболее стандартными операциями; оно будет дополняться по мере надобности в процессе обсуждния каждой операции. В #8.5.6 описываются преобразования, оределяемые пользователем.

6.1 Символы и Целые

   Символ или короткое целое могут использоваться, если может использоваться целое. Во всех случаях значение преобразуется к целому. Преобразование короткого целого к длинному всегда включает в себя знаковое расширение; целые являются величинами со знаком. Содержат символы знаковый раряд или нет, является машинно зависимым, см. #2.6. Более яный тип unsigned char ограничивает изменение значения от 0 до машинно зависимого максимума.
   В машинах, где символы рассматриваются как имеющие знак (знаковые), символы множества кода ASCII являются положителными. Однако, символьная константа, заданная восьмеричной escпоследовательностью подвергается знаковому расширению и может стать отрицательным числом; так например, '\377' имеет значение -1.
   Когда длинное целое преобразуется в короткое или в char, оно урезается влево; избыточные биты просто теряются.

6.2 Float и Double

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

6.3 Плавающие и Целые

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

6.4 Указатели и Целые

   Выражение целого типа можно прибавить к указателю или вычесть из него. В таком случае первый преобразуется, как указывается при обсуждении операции сложения.
   Можно производить вычитание над двумя указателями на объекты одного типа; в этом случае результат преобразуется к типу int или long в зависимости от машины, см. #7.4.

6.5 Unsigned

   Всегда при сочетании целого без знака и обычного целого обычное целое преобразуется к типу unsigned и результат имеет тип unsigned. Значением является наименьшее целое без знака, равное целому со знаком (mod 2**(размер слова)) (т.е. по мдулю 2**(размер слова)). В дополнительном двоичном предсталении это преобразование является пустым, и никаких реальных изменений в двоичном представлении не происходит.
   При преобразовании целого без знака в длинное значение результата численно совпадает со значением целого без знака. Таким образом, преобразование сводится к дополнению нулями слева.

6.6 Арифметические Преобразования

   Большое количество операций вызывают преобразования и дают тип результата одинаковым образом. Этот стереотип будет называться «обычным арифметическим преобразованием».
   Во-первых, любые операнды типа char, unsigned char или short преобразуются к типу int.
   Далее, если один из операндов имеет тип double, то дргой преобразуется к типу double и тот же тип имеет рзультат.
   Иначе, если один из операндов имеет тип unsigned long, то другой преобразуется к типу unsigned long и таков же тип результата.
   Иначе, если один из операндов имеет тип long, то другой преобразуется к типу long и таков же тип результата.
   Иначе, если один из операндов имеет тип unsigned, то другой преобразуется к типу unsigned и таков же тип рзультата.
   Иначе оба операнда должны иметь тип int и таков же тип результата.

6.7 Преобразования Указателей

   Везде, где указатели присваиваются, инициализируются, сравниваются и т.д. могут выполняться следующие преобразовния.
   Константа 0 может преобразовываться в указатель, и грантируется, что это значение породит указатель, отлиный от указателя на любой объект.
   Указатель любого типа может преобразовываться в void*.
   Указатель на класс может преобразовываться в указатель на открытый базовый класс этого класса, см. #8.5.3.
   Имя вектора может преобразовываться в указатель на его первый элемент.
   Идентификатор, описанный как «функция, возвращающая ...», всегда, когда он не используется в позиции имени функции в вызове, преобразуется в «указатель на функцию, возвращающую ...».

6.8 Преобразования Ссылок

   Везде, где инициализируются ссылки, может выполняться следующее преобразование.
   Ссылка на класс может преобразовываться в ссылку на отрытый базовый класс этого класса, см. #8.6.3.

7. Выражения

   Приоритет операций в выраженях такой же, как и порядок главных подразделов в этом разделе, наибольший приоритет у первого. Так например, выражения, о которых говорится как об операндах операции + (#7.4) – это те выражения, которые опрделены в ##7.1-7.4. Внутри каждого подраздела операции имеют одинаковый приоритет. В каждом подразделе для рассматриваемых в нем операций определяется их левая или правая ассоциатиность (порядок обработки операндов). Приоритет и ассоциатиность всех операций собран вместе в описании грамматики в #14.
   В остальных случаях порядок вычисления выражения неопрделен. Точнее, компилятор волен вычислять подвыражения в том
   порядке, который он считает более эффективным, даже если повыражения вызывают побочные эффекты. Порядок возникновения побочных эффектов неопределен. Выражения, включающие в себя коммутативные и асссоциативные операции (*, +, amp;, !, ^), мгут быть реорганизованы произвольным образом, даже при налчии скобок; для задания определенного порядка вычисления вражения необходимо использовать явную временную переменную.
   Обработка переполнения и контроль деления при вычислении выражения машинно зависимы. В большинстве существующих реалзаций С++ переполнение целого игнорируется; обработка деления на 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 [ выражение ] выражение унарная_операция: одна из * amp; – ! ~ ++ –
   Унарная операция * означает косвенное обращение: выражение должно быть указателем и результатом будет lvalue, ссылающееся на объект, на который указывает выражение. Если выражение имеет тип «указатель на ...», то тип результата есть «...».
   Результатом унарной операции amp; является указатель на объект, на который ссылается операнд. Операнд должен быть 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.2), возможно, заключенное в скобки, за которым идет заключенное в скобки выражение (или спсок_выражений, если тип является классом с соответствующим образом описанным конструктором #8.5.5) влечет преобразование значения выражения в названный тип. Чтобы записать преобразвание в тип, не имеющий простого имени, имя_типа (#8.7) долно быть заключено в скобки. Если имя типа заключено в скобки, выражение заключать в скобки необязательно. Такая запись нзывается приведением к типу.
   Указатель может быть явно преобразован к любому из целчисленных типов, достаточно по величине для его хранения. То, какой из int и long требуется, является машинно зависимым. Отобразующая функция также является машинно зависимой, но предполагается, что она не содержит сюрпризов для того, кто знает структуру адресации в машине. Подробности для некоторых конкретных машин были приведены в #2.6.
   Объект целочисленного типа может быть явно преобразован в указатель. Отображающая функция всегда превращает целое, полученное из указателя, обратно в тот же указатель, но в отальных случаях является машинно зависимой.
   Указатель на один тип может быть явно преобразован в указатель на другой тип. Использование полученного в резултате указателя может привести к исключительной ситуации адресации, если исходный указатель не указывает на объект, сооветствующим образом выравненный в памяти. Гарантируется, что указатель на объект данного размера может быть преобразован в указатель на объект меньшего размера и обратно без изменений. Различные машины могут различаться по числу бит в указателях и требованиям к выравниванию объектов. Составные объекты вравниваются по самой строгой границе, требуемой каким-либо из его составляющих.
   Объект может преобразовываться в объект класса только если был описан соответствующий конструктор или операция пробразования (#8.5.6).
   Объект может явно преобразовываться в ссылочный тип amp;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 Мультипликативные Операции

   Мультипликативные операции *, / и % группируют слева направо. Выполняются обычные арифметические преобразования.
   мультипликативное_выражение: выражение * выражение выражение / выражение выражение % выражение
   Бинарная операция * определяет умножение. Операция * ассоциативна и выражения с несколькими умножениями на одном уровне могут быть реорганизованы компилятором. Бинарная операция / определяет деление. При делении пложительных целых округление осуществляется в сторону 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 не означает то, чем кажется.
   выражение_отношения: выражение « выражение выражение » выражение выражение «= выражение выражение »= выражение
   Операции « (меньше чем), » (больше чем), «= и »= все дют 0, если заданное соотношение ложно, и 1, если оно истинно. Тип результата int. Выполняются обычные арифметические преоразования. Могут сравниваться два указателя; результат завсит от относительного положения объектов, на которые указывют указатели, в адресном пространстве. Сравнение указателей переносимо только если указатели указывают на объекты одного массива.

7.7 Операции Равенства

   выражение_равенства: выражение == выражение выражение != выражение
   Операции == и != в точности аналогичны операциям сравнния за исключением их низкого приоритета. (Так, a«b == c«d есть 1 всегда, когда a«b и c«d имеют одинаковое истинностное значение.)
   Указатель может сравниваться с 0.

7.8 Операция Побитовое И

   И-выражение: выражение amp; выражение
   Операция amp; ассоциативна, и выражения, содержащие amp;, мгут реорганизовываться. Выполняются обычные арифметические преобразования; результатом является побитовая функция И опрандов. Операция применяется только к целым операндам.

7.9 Операция Побитовое Исключающее ИЛИ

   исключающее_ИЛИ_выражение: выражение ^ выражение
   Операция ^ ассоциативна, и выражения, содержащие ^, мгут реорганизовываться. Выполняются обычные арифметические преобразования; результатом является побитовая функция исключающее ИЛИ операндов. Операция применяется только к целым операндам.

7.10 Операция Побитовое Включающее ИЛИ

   включающее_ИЛИ_выражение: выражение ! выражение
   Операция ! ассоциативна, и выражения, содержащие !, мгут реорганизовываться. Выполняются обычные арифметические преобразования; результатом является побитовая функция вклчающее ИЛИ операндов. Операция применяется только к целым операндам.

7.11 Операция Логическое И

   логическое_И_выражение: выражение amp; amp; выражение
   Операция amp; amp; группирует слева направо. Она возвращает 1, если оба операнда ненулевые, и 0 в противном случае. В протвоположность операции amp; операция amp; amp; гарантирует вычисление слева направо; более того, второй операнд не вычисляется, ели первый операнд есть 0.
   Операнды не обязаны иметь один и тот же тип, но каждый из них должен иметь один из основных типов или быть указатлем. Результат всегда имеет тип int.

7.12 Операция Логическое ИЛИ

   логическое_ИЛИ_выражение: выражение !! выражение
   Операция !! группирует слева направо. Она возвращает 1, если хотя бы один из ее операндов ненуелвой, и 0 в противном случае. В противоположность операции ! операция !! гарантирет вычисление слева направо; более того, второй операнд не вычисляется, если первый операнд не есть 0.