Выражение и l-выражение

advertisement
Выражение и l-выражение
Доступ к объектам и функциям обеспечивается выражениями, которые в этом случае
ссылаются на объекты.
Выражение, которое обеспечивает ссылку на константу, переменную или функцию,
называется l-выражением. Имя объекта в C++ является частным случаем l-выражения.
В C++ допускается изменение значений переменных. Значения констант и функций в C++
изменению не подлежат. l-выражение называется модифицируемым l-выражением, либо
леводопустимым выражением, если только оно не ссылается на функцию, массив или
константу. Таким образом, леводопустимыми выражениями называют l-выражения,
которые ссылаются на переменные.
1. Унарные операции
1.1. Адресные операции
&
Операция получения адреса операнда.
Операндом может быть любое l-выражение. Операция возвращает адрес объекта или
функции, на который ссылается операнд. Операция невыполнима по отношению к
объектам, определённым со спецификатором register, поскольку существует вероятность
того, что они не располагаются в памяти и не имеют определённого адреса.
*
Операция обращения по адресу или операция косвенного обращения.
Операндом может быть выражение, значением которого является адрес. Операция
косвенного обращения называется также операцией разыменования, поскольку позволяет
обращаться к объекту не употребляя при этом имени объекта.
1.2. Операции преобразования знака
-
Операция унарный минус.
Операндом может быть любое выражение со значением арифметического типа. Операция
преобразует положительное значение в отрицательное значение и наоборот.
+
Операция унарный плюс.
Операндом может быть любое выражение со значением арифметического типа. Операция
в буквальном смысле ничего не делает. В некоторых источниках её существование
объясняется тем, что она ведена для симметрии с унарным минусом. Однако, не совсем
понятно, что имеется в виду под понятием симметрии в формальном языке.
В C++ существует возможность присвоения (мы ещё уделим внимание этой интуитивно
понятной операции) переменной отрицательного значения. Старательные и аккуратные
программисты могут особо подчеркнуть и тот факт, что переменной присвоено
положительное значение. Для этого в C++ и была реализована специальная операция
унарный плюс.
В формальном языке каждая лексема имеет своё название и назначение. И этот самый
плюс-украшение также является операцией. А дальше - рушится иллюзия симметрии
унарных операций. Унарный минус работает. Он эквивалентен умножению значения
операнда на -1. Унарный плюс эквивалентен умножению значения операнда на +1. Он
ничего не делает.
1.3. Побитовые операции
~
Операция инвертирования или побитового отрицания.
Операндом может быть любое выражение интегрального типа. Операция обеспечивает
побитовое инвертирование двоичного кода.
!
Операция логического отрицания.
Операндом может быть любое выражение со значением арифметического типа. Для
непосредственного обозначения логических значений в C++ используются целочисленные
значения 0 - ложь и 1 - истина. Кроме того, в логических операциях любое ненулевое
значение операнда ассоциируется с единицей. Поэтому отрицанием нулевого значения
является 1, т.е. истина, а отрицанием любого ненулевого значения оказывается 0, т.е.
ложь.
1.4. Операция определения размера
sizeof Операция определения размера объекта или типа.
В C++ различают два варианта этой операции. В первом случае операндом может быть
любое l-выражение. Это выражение записывается справа от символа операции. Значением
выражения является размер конкретного объекта в байтах. Во втором случае операндом
является имя типа. Это выражение записывается в скобках непосредственно за символом
операции. Значением выражения является размер конкретного типа данных в байтах.
Результатом этой операции является константа типа size_t. Этот производный
целочисленный беззнаковый тип определяется конкретной реализацией.
1.5. Операции увеличения и уменьшения значения
++
Инкремент, или операция увеличения на единицу.
Точнее, на величину, кратную единице, поскольку всё зависит от типа операнда. Операция
имеет дополнительный эффект - она изменяет значение операнда. Поэтому операндом
здесь может быть только леводопустимое выражение арифметического типа, либо типа
указателя. В C++ различают префиксную и постфиксную операции инкремента.
В префиксной форме увеличение значения операнда производится до определения
значения выражения. В результате значение выражения и значение операнда совпадают.
В постфиксной форме увеличение значения операнда производится после определения
значения выражения. Поэтому значение выражения оказывается меньше значенния
операнда.
В выражении с префиксной операцией увеличения знак ++ записывается слева от
операнда, в выражении с постфиксной операцией - справа.
Операция инкремента по отношению к указателю увеличивает значение операнда на
количество байт, равное длине одного объекта этого типа, то есть действительно на
величину, кратную единице.
--
Операция уменьшения значения операнда
на величину, кратную единице (декремент).
Эта операция в буквальном смысле симметрична операции инкремента. Имеет
аналогичный дополнительный эффект, соответствующие ограничения для операнда
(свойство леводопустимости, арифметический тип, либо тип указателя, префиксную и
постфиксную формы, изменение значения адреса).
В выражении с префиксной операцией увеличения знак -- записывается слева от операнда,
в выражении с постфиксной операцией - справа.
1.6. Операции динамического распределения памяти
new
Операция выделения памяти.
Позволяет выделить и сделать доступным участок в динамической памяти. В качестве
операнда используется имя типа и, возможно, выражение инициализатор. Операция
возвращает адрес размещённого в памяти объекта.
delete Операция освобождения памяти.
Освобождает ранее выделенную с помощью операции new область динамической памяти.
В качестве операнда используется адрес освобождаемой области памяти.
1.7. Операция доступа
::
Операция доступа.
Обеспечивает обращение к именованной глобальной области памяти, находящейся вне
области видимости. Эта операция применяется при работе с одноимёнными объектами,
расположенными во вложенных областях действия имён. Когда объект во внутренней
области действия имени скрывает одноименный объект, областью действия которого
является файл. Например:
int m; // Глобальная переменная.
:::::
int mmm()
{
int m;
// Локальная переменная.
m = 100; // Присвоение значения локальной переменной.
::m = 125; // Присвоение значения глобальной
// переменной m, находящейся вне области видимости
// имени.
}
Не следует испытывать никаких иллюзий относительно возможностей этой операции.
Операция обеспечивает доступ лишь к глобальным, естественно, ранее объявленным
объектам, независимо от степени вложенности области действия. Поэтому она не обладает
свойством транзитивности. Выражения вида ::(::(::m)) воспринимаются транслятором как
ошибочные.
2. Бинарные операции
2.1. Аддитивные операции
+
Операция сложения.
Операция используется с операндами арифметического типа. Один из операндов может
иметь тип указателя. В любом случае значением выражения является либо сумма
значений, либо сумма адреса и целочисленного значения, кратного размерам данного
типа.
Результат сложения указателя с целым числом эквивалентен результату
соответствующего количества операций инкремента, пррименённых к укаазателю.
Тип и значение результата выражения любой бинарной операции определяется в
зависимости от принятых в C++ соглашений о преобразовании типов, о которых будет
сказано ниже.
-
Операция вычитания.
Симметричная по отношению к операции сложения бинарная операция.
2.2. Мультипликативные операции
*
Операция умножения.
Операндами могут быть выражения арифметического типа. Значением выражения
является произведение значений. Тип результата выражения любой бинарной операции
определяется в зависимости от принятых в C++ процедур преобразования типов данных.
/
Операция деления.
Операндами могут быть выражения арифметического типа. Значением выражения
является частное от деления значения первого операнда на второй операнд. Тип
результата выражения любой бинарной операции определяется в зависимости от
принятых в C++ процедур преобразования типов данных.
%
Операция получения остатка от деления
целочисленных операндов (деление по модулю).
Операндами могут быть выражения арифметического типа. В процессе выполнения
операции операнды приводятся к целому типу. При неотрицательных операндах остаток
положительный. В противном случае знак остатка определяется в зависимости от
реализации. Известно, что для Borland C++
15%6=3, (-15)%6=-3, 15%(-6)=3, (-15)%(-6)=-3.
При ненулевом делителе для целочисленных операндов выполняется соотношение
(a/b)*b+a%b=a
2.3. Операции сдвига
Эти операции определены только для целочисленных операндов.
<<
Операция левого сдвига.
Операндами могут быть выражения интегрального типа. Значением выражения является
битовое представление левого операнда, сдвинутое влево на количество разрядов, равное
значению правого операнда. При левом сдвиге на i разрядов первые i разрядов левого
операнда теряются, последние i разрядов левого операнда заполняются нулями.
>>
Операция правого сдвига.
Операндами могут быть выражения интегрального типа. Значением выражения является
битовое представление левого операнда, сдвинутое вправо на количество разрядов, равное
значению правого целочисленного операнда. При правом сдвиге на i разрядов первые i
разрядов левого операнда заполняются нулями, если левый операнд имеет беззнаковый
тип или имеет неотрицательное значение, в противном случае значение определяется
реализацией. Последние i разрядов левого операнда теряются.
2.4. Поразрядные операции
Поразрядные операции определены только для целочисленных операндов.
&
Поразрядная конъюнкция битовых представлений
значений целочисленных операндов.
Операндами могут быть выражения интегрального типа. Значение выражения
вычисляется путём побитовых преобразований и зависит от значений соответствующих
битов левого и правого операнда. Следующая таблица однозначно определяет операцию
поразрядной конъюнкции.
Бит левого операнда Бит правого операнда Результат операции &
|
1
1
1
1
0
0
0
1
0
0
0
0
Поразрядная дизъюнкция битовых представлений
значений целочисленных операндов.
Операндами могут быть выражения интегрального типа. Значение выражения
вычисляется путём побитовых преобразований и зависит от значений соответствующих
битов левого и правого операнда. Следующая таблица определяет операцию поразрядной
дизъюнкции.
Бит левого операнда Бит правого операнда Результат операции |
1
1
1
1
0
1
0
1
1
0
^
0
0
Поразрядная исключающая дизъюнкция битовых
представлений значений целочисленных операндов.
Операндами могут быть выражения интегрального типа. Значение выражения
вычисляется путём побитовых преобразований и зависит от значений соответствующих
битов левого и правого операнда. Следующая таблица определяет операцию поразрядной
исключающей дизъюнкции.
Бит левого операнда Бит правого операнда Результат операции ^
1
1
0
1
0
1
0
1
1
0
0
0
2.5. Операции сравнения
<,<=,>,>=,==,!= Меньше, меньше равно, больше,
больше равно, равно, не равно.
Операции сравнения определены на множестве операндов арифметического типа.
Допускается также сравнение значений адресов в памяти ЭВМ. Следующая таблица
демонстрирует зависимость результата сравнения от значений операндов Val1 и Val2.
Результат сравнения всегда целочисленный и может принимать одно из двух значений: 0
и 1. При этом 0 означает ложь, а 1 - истину.
Операция 1, если
0, если
<
Val1 меньше Val2
Val1 больше или равно Val2
<=
Val1 меньше или равно Val2 Val1 больше Val2
>
Val1 больше Val2
>=
Val1 больше или равно Val2 Val1 меньше Val2
==
Val1 равно Val2
Val1 не равно Val2
!=
Val1 не равно Val2
Val1 равно Val2
Val1 меньше или равно Val2
2.6. Логические бинарные операции
&&,||
И, ИЛИ.
Логические бинарные операции объединяют выражения сравнения со значениями истина
(!=0) и ложь (==0). Результат операций приведён в следующей таблице
Первый операнд Второй операнд && ||
Истина
истина
1
1
Истина
ложь
0
1
Ложь
истина
0
1
Ложь
ложь
0
0
2.7. Операция присваивания
=
Простая форма операции присваивания.
Левый операнд операции присваивания является леводопустимым выражением.
В качестве правого операнда операции присваивания может выступать любое выражение.
Значение правого операнда присваивается левому операнду. Значение выражения
оказывается равным значению правого операнда. Не существует никаких ограничений на
структуру этого операнда. Правый операнд может состоять из множества выражений,
соединенных операциями присвоения:
An=…=A3=A2=A1;
где A1, A2, A3, …, An являются выражениями. Для определения значений выражений
подобной структуры в C++ существуют правила группирования операндов выражений
сложной структуры (эти правила подробно будут описаны ниже). В соответствии с одним
из этих правил операнды операции присвоения группируются справа налево:
An=(An-1=…=(A3=(A2=A1))…);
Очевидно, что в таком выражении все операнды, кроме самого правого, должны быть
модифицируемыми l-выражениями. В результате выполнения этого выражения операндам
An, An-1, … A3, A2 будет присвоено значение операнда A1.
2.8. Специальные формы операций присваивания
В процессе трансляции выражений на этапе генерации кода транслятор строит
последовательности машинных кодов, реализующие закодированные в выражениях
действия. Например, при трансляции выражения
A = A + 125
транслятор, прежде всего, генерирует код для вычисления значения выражения A + 125 и
присвоения результата переменной A. При этом фрагмент кода, вычисляющий адрес
переменной A дважды войдёт во множество команд процессора, реализующих это
выражение.
В целях упрощения структуры подобных операторов в C++ применяются
комбинированные (или сокращённые) формы операторов присваивания.
*=
Операция присвоения произведения.
A *= B
Присвоение левому операнду произведение значений левого и правого операндов.
Операция по своему результату эквивалентна простой форме операции присвоения, у
которой правый операнд имеет вид произведения A * B, левый операнд имеет вид A. При
этом A является модифицируемым l-выражением:
A = A * B
/=
Операция присвоения частного от деления.
A /= B + 254
Присвоение левому операнду частного от деления значения левого операнда на значение
выражения правого операнда. Операция по своему результату эквивалентна простой
форме операции присвоения, у которой правый операнд имеет вид
A / (B + 254)
левый операнд прелставляется выражением A. Очевидно, что при этом A должно быть
модифицируемым l-выражением:
A = A / (B + 254)
%=
Операция присвоения остатка от деления.
A %= B
Левый операнд должен быть модифицируемым l-выражением.
+=
Операция присвоения суммы.
A += B
Левый операнд должен быть модифицируемым l-выражением.
-=
Операция присвоения разности.
A -= B
Левый операнд должен быть модифицируемым l-выражением.
<<=
Операция присвоения результата операции побитового сдвига влево на
количество бит, равное значению правого целочисленного
операнда.
A <<= B
Левый операнд должен быть модифицируемым l-выражением.
>>=
Операция присвоения результата операции побитового сдвига вправо
на количество бит, равное значению правого
целочисленного операнда.
A <<= B
Левый операнд должен быть модифицируемым l-выражением.
&=
Операция присвоения результата поразрядной конъюнкции битовых
представлений значений целочисленных операндов.
A &= B
Левый операнд должен быть модифицируемым l-выражением.
|=
Операция присвоения результата поразрядной дизъюнкции битовых
представлений значений целочисленных операндов.
A |= B
Левый операнд должен быть модифицируемым l-выражением.
^=
Операция присвоения результата поразрядной исключающей дизъюнкции
битовых представлений значений целочисленных операндов.
A ^= B
Левый операнд должен быть модифицируемым l-выражением.
Специальные формы операций присвоения позволяют не только изменять структуру
выражений, но и оптимизировать создаваемый транслятором программный код. Фрагмент
кода, определяющий адрес левого операнда выражения встречается в соответствующем
множестве команд процессора лишь один раз.
2.9. Операции выбора компонентов структурированного объекта
К операциям выбора компонентов структурированного объекта относятся:
.
->
Операция прямого выбора - точка.
Операция косвенного выбора.
Об этих операциях будет сказано позже, после определения понятия класса и объектапредставителя класса.
2.10. Операции обращения к компонентам класса
К операциям обращения к компонентам класса относятся:
.*
Операция обращения к компоненте класса по имени объекта
или ссылки на объект (левый операнд операции) и указателю
на компоненту класса (правый операнд операции).
->*
Операция обращения к компоненте класса по указателю на
объект (левый операнд операции) и указателю на компоненту
класса (правый операнд операции).
::
Операция доступа к компоненте класса по имени класса и имени
компоненты.
2.11. Операция управления процессом вычисления значений
,
Операция запятая.
Группирует выражения слева направо. Разделённые запятыми выражения вычисляются
последовательно слева направо, в качестве результата сохраняются тип и значение самого
правого выражения.
A &= B, A * B, -A
Эта операция формально также является бинарной операцией, хотя операнды этой
операции абсолютно не связаны между собой
2.12. Операция вызова функции
()
Операция вызова.
Играет роль бинарной операции при вызове функции. Левый операнд представляет собой
выражение, значением которого является адрес функции. Правый операнд является
разделённым запятыми списком выражений, определяющих значения параметров.
2.13. Операция явного преобразования типа
()
Операция преобразования (или приведения) типа.
Эта бинарная операция в контексте так называемого постфиксного выражения и в
контексте выражения приведения обеспечивает изменение типа значения выражения,
представляемого вторым операндом. Информация о типе, к которому преобразуется
значение второго операнда, кодируется первым выражением, которое является
спецификатором типа. Существуют две формы операции преобразования типа:
каноническая, при которой в скобки заключается первый операнд (в выражениях
приведения), и функциональная (в постфиксных выражениях), при которой в скобки
заключается второй операнд. При функциональной форме операции преобразования типа
спецификатор типа представляется одним идентификатором. Для приввведениия значения
к типу unsigned long следует использовать лишь каноническую форму операции
преобразования. Механизм преобразования типа рассматривается ниже
2.14. Операция индексации
[]
Операция индексации.
Играет роль бинарной операции при индексации элементов массива (определение массива
приводится ниже). Левый операнд представляет собой выражение, значением которого
является адрес первого элемента массива. Правый операнд является выражением,
определяющим значение индекса, т.е. смещения относительно первого элемента массива.
2. Операция с тремя операндами
?:
Условная операция.
Единственная в C++ операция с тремя операндами. Первое выражение-операнд
располагается слева от знака ?, второе выражение-операнд располагается между знаками ?
и :, третье выражение-операнд - справа от знака :. Выполнение условной операции
начинается с вычисления значения самого левого операнда. Если его значение
оказывается отличным от 0, то вычисляется значение второго операнда, которое и
становится значением выражения. Если значение первого операнда оказывается равным 0,
то вычисляется значение третьего операнда, и тогда это значение становится значением
выражения.
(x < 10)? x = 25: x++
3. Операция typeid
Операция typeid обеспечивает динамическую идентификацию типов. Пока лишь
упомянем о её существовании, поскольку её описание требует углублённых познаний в
области объектно-ориентированного программирования.
Выражение
Выражение ::= ВыражениеПрисваивания
::= Выражение , ВыражениеПрисваивания
В контексте, где запятая выступает в роли разделителя, например, списке параметров
вызова функции или в списке инициализации, запятая как знак операции может появиться
только в круглых скобках:
MyFun(a, (w = 5, w + 9), c)
/* Выражение вызова функции с тремя параметрами. Значение второго параметра
задаётся выражением, значение которого равно 14. */
Большая часть выражений представляет собой сочетание символов операций и операндов.
Однако это вовсе не означает, что в ходе вычисления значения подобных выражений
непременно будут применяться соответствующие операции. Выражение - это видимость.
В каждом конкретном случае всё зависит от типа операндов. Если операнды оказываются
операндами основного типа, либо указателями, то можно предположить, что при
вычислении его значения будет выполняться конкретная операция C++. Если же операнды
выражения оказываются операндами производного типа, символ операции может
оказаться эквивалентным вызову операторной функции. И кто знает, что делает эта самая
операторная функция.
Выражения присваивания
ВыражениеПрисваивания ::= УсловноеВыражение
::= УнарноеВыражение ОперацияПрисваивания ВыражениеПрисваивания
ОперацияПрисваивания ::= = | *= | /= | %= | += | -= |
>>= | <<= | &= | ^= | |=
Условные и логические выражения
УсловноеВыражение ::= ВыражениеИлиЛогическое
::= ВыражениеИлиВключающее ? Выражение : УсловноеВыражение
ВыражениеИЛогическое ::= ВыражениеИлиВключающее
::= ВыражениеИЛогическое && ВыражениеИлиВключающее
ВыражениеИлиЛогическое ::= ВыражениеИЛогическое
::= ВыражениеИлиЛогическое || ВыражениеИЛогическое
Побитовые выражения
ВыражениеИлиВключающее ::= ВыражениеИлиИсключающее
::= ВыражениеИлиВключающее | ВыражениеИлиИсключающее
ВыражениеИлиИсключающее ::= ВыражениеИ
::= ВыражениеИлиИсключающее ^ ВыражениеИ
ВыражениеИ ::= ВыражениеРавенства
::= ВыражениеИ & ВыражениеРавенства
Выражения равенства
ВыражениеРавенства ::= ВыражениеОтношения
::= ВыражениеРавенства == ВыражениеОтношения
::= ВыражениеРавенства != ВыражениеОтношения
Выражения отношения
ВыражениеОтношения ::=
::=
::=
::=
ВыражениеСдвига
ВыражениеОтношения < ВыражениеСдвига
ВыражениеОтношения > ВыражениеСдвига
ВыражениеОтношения <= ВыражениеСдвига
::= ВыражениеОтношения >= ВыражениеСдвига
Выражения сдвига
ВыражениеСдвига ::= АддитивноеВыражение
::= ВыражениеСдвига << АддитивноеВыражение
::= ВыражениеСдвига >> АддитивноеВыражение
Аддитивные выражения
АддитивноеВыражение ::= МультипликативноеВыражение
::= АддитивноеВыражение + МультипликативноеВыражение
::= АддитивноеВыражение - МультипликативноеВыражение
Мультипликативные выражения
МультипликативноеВыражение ::= pmВыражение
::= МультипликативноеВыражение * pmВыражение
::= МультипликативноеВыражение / pmВыражение
::= МультипликативноеВыражение % pmВыражение
Выражения с указателями
pmВыражение ::= ВыражениеПриведения
::= pmВыражение .* ВыражениеПриведения
::= pmВыражение ->* ВыражениеПриведения
Выражение приведения
Для преобразования данного значения к определённому типу используется выражение
явного преобразования (одна из разновидностей постфиксного выражения). Оно имеет
вид функциональной формы записи: имя типа, за которым в скобочках записывается
список выражений.
Кроме того, в C++ существует каноническая форма записи выражения приведения.
ВыражениеПриведения ::= УнарноеВыражение
::= (ИмяТипа) ВыражениеПриведения
Основные ограничения на типы операндов и особенности выполнения соответствующих
операций также ранее уже обсуждались.
Унарное выражение
УнарноеВыражение ::= ПостфиксноеВыражение
::= ++ УнарноеВыражение
::= -- УнарноеВыражение
::= УнарнаяОперация ВыражениеПриведения
::= sizeof УнарноеВыражение
::= sizeof (ИмяТипа)
::= ВыражениеРазмещения
::= ВыражениеОсвобождения
УнарнаяОперация ::= * | & | + | - | ! | ~
Унарные выражения группируются справа налево.
Вторая и третья БНФ являются основой для построения префиксных выражений
увеличения и уменьшения (инкремента и декремента). Символ операции в выражении
инкремента и декремента вовсе не означает, что в ходе вычисления значения выражения к
операндам будут применяться операции уменьшения и увеличения. В сочетании с
операндами производных типов определение значений этих выражений сопровождается
вызовами специальных (операторных) функций.
В выражениях, представленных четвёртой БНФ, унарная операция * является операцией
разыменования. Типом выражения приведения является указатель на объект типа X, а это
указывает на то, что описываемое значение является l-выражением. Значением выражения
является значение размещённого в памяти объекта. Если типом операнда является тип
указатель на объект типа X, то типом выражения является непосредственно тип X.
Результатом операции & является адрес объекта, представленного операндом. При этом
операнд операции может оказаться либо l-выражением, либо квалифицированным
именем. Но об этом позже.
Далее приводится множество БНФ, определяющих синтаксис выражений размещения и
освобождения. У этих выражений достаточно сложная семантика. Детально разобрать их
в данный момент мы пока просто не сможем. На этом этапе придётся ограничиться лишь
самыми необходимыми сведениями.
Выражение размещения
ВыражениеРазмещения
::= [::] new [Размещение] ИмяТипаNew [ИнициализаторNew]
::= [::] new [Размещение] (ИмяТипа) [ИнициализаторNew]
Размещение ::= (СписокВыражений)
ИмяТипаNew ::= СписокСпецификаторовТипа [ОписательNew]
ОписательNew ::= * [СписокCVОписателей] [ОписательNew]
::= [ОписательNew] [Выражение]
ИмяТипа ::= СписокСпецификаторовТипа [АбстрактныйОписатель]
СписокСпецификаторовТипа ::=
СпецификаторТипа [СписокСпецификаторовТипа]
СпецификаторТипа ::= ИмяПростогоТипа
::= const
::= volatile
::= *****
Существуют также спецификаторы типа, обозначаемые нетерминальными символами
СпецификаторКласса, СпецификаторПеречисления и УточнённыйСпецификаторТипа:
СпецификаторТипа ::= СпецификаторКласса
::= СпецификаторПеречисления
::= УточнённыйСпецификаторТипа
Об этих спецификаторах позже. Нетерминальный символ ИмяПростогоТипа представляет
все известные в C++ имена основных типов. Кроме того, именами простого типа также
считаются синтаксические конструкции, обозначаемые нетерминальными символами
ПолноеИмяКласса и КвалифицированноеИмяТипа. Все эти имена строятся на основе
идентификаторов, возможно, в сочетании с операцией ::.
ИмяПростогоТипа ::= ПолноеИмяКласса
::= КвалифицированноеИмяТипа
::= *****
ПолноеИмяКласса ::= КвалифицированноеИмяКласса
::= :: КвалифицированноеИмяКласса
Наконец мы можем описать, что собой представляет квалифицированное имя. Это
система имён, разделённых операцией :: (обозначает класс, объявленный внутри другого
класса).
КвалифицированноеИмя ::= КвалифицированноеИмяКласса :: Имя
КвалифицированноеИмяКласса ::= ИмяКласса
::= ИмяКласса::КвалифицированноеИмяКласса
КвалифицированноеИмяТипа ::= ОписанноеИмяТипа
::= ИмяКласса :: КвалифицированноеИмяТипа
ИмяКласса ::= Идентификатор
ОписанноеИмяТипа ::= Идентификатор
ИнициализаторNew ::= ([СписокИнициализаторов])
СписокИнициализаторов ::= [СписокИнициализаторов,] Инициализатор
Нетерминал АбстрактныйОписатель нам известен. Он используется для описания общей
структуры объекта в тех случаях, когда имя объекта не играет никакой роли и может быть
опущено. Например, в объявлениях.
Выражение размещения обеспечивает выполнение действий, в результате которых в
динамической памяти создаётся объект определённого типа.
При этом отводится память, необходимая для размещения объекта. Сам объект, возможно,
инициализируется. После чего возвращается указатель на размещённый в динамической
памяти объект.
При этом время жизни объекта, созданного в результате выполнения выражения
размещения, не ограничивается областью действия, в которой он был создан. Значением
выражения является указатель на созданный объект.
При создании динамического массива (множества объектов одного типа, расположенных
друг за другом в одной области динамической памяти), значением выражения размещения
оказывается значение указатель на первый элемент массива. При этом соответствующий
ОписательNew в квадратных скобках должен содержать информацию о размерах
выделяемой области памяти. Естественно, выражение в квадратных скобках должно быть
выражением целого типа. Никаких других ограничений на это выражение не
накладывается.
…new int[25]…
…new int* [val1 + val2]…
…new float** [x]…
Выражение освобождения
ВыражениеОсвобождения ::= [::] delete ВыражениеПриведения
::= [::] delete [] ВыражениеПриведения
Это выражение не имеет определённого значения. А значит и о типе выражения мало что
можно сказать определённого. Возможно, что оно является выражением типа void.
Именно так обозначается специальный тип, который называется также пустым типом.
Операция delete работает с динамической памятью. Она способна прочитать скрытую
дополнительную информацию о ранее размещённом в динамической памяти с помощью
операции new объекте. Поэтому операция delete требует всего одного операнда указателя
на объект.
Последствия выполнения операции delete над указателем непредсказуемы и ужасны, если
он ссылается на объект, который ранее не был размещён с помощью операции new.
Гарантируется безопасность действия операции delete над нулевым указателем. Для
удаления массивов используется специальный вариант операции с квадратными скобками.
Удаление констант считается ошибкой. Она фиксируется на стадии трансляции. Позже мы
обсудим назначение разделителя в выражениях освобождения и размещения '::'.
Постфиксное выражение
Постфиксное выражение определяется на основе первичного выражения.
Соответствующее множество БНФ включает множество разнообразных альтернатив.
ПостфиксноеВыражение ::= ПервичноеВыражение
::= ПостфиксноеВыражение [Выражение]
::= ПостфиксноеВыражение ([СписокВыражений])
::= ПостфиксноеВыражение.Имя
::= ПостфиксноеВыражение->Имя
::= ПостфиксноеВыражение++
::= ПостфиксноеВыражениеСписокВыражений ::= ВыражениеПрисваивания
::= СписокВыражений, ВыражениеПрисваивания
Первичное выражение является частным случаем постфиксного выражения. Вторым в
списке возможных альтернатив постфиксных выражений является БНФ, представляющая
различные варианты выражений индексации. Это выражение строится из двух выражений
- постфиксного (первичного) выражения, за которым следует ещё одно выражение (второй
операнд операции индексации), заключённое в квадратные скобки. Обычно первое
выражение представляет указатель на объект типа X (пока неважно, какого типа объект),
второе выражение является выражением интегрального типа. Это выражение называется
индексом.
Следующей альтернативой является БНФ, представляющая выражения вызова. В нём
также участвуют два выражения. Первое выражение может быть представлено именем
функции, указателем или ссылкой (частный случай указателя). Список выражений в
круглых скобках (второй операнд операции вызова) определяет значения множества
параметров, которые используются при означивании соответствующих параметров
вызываемой функции.
Выражения явного преобразования типа (в функциональной форме) являются ещё одним
вариантом постфиксного выражения. Это выражение начинается с имени простого типа
(простой тип - не обязательно основной). В круглых скобках заключается список
выражений (второй операнд операции преобразования), на основе которого формируется
значение типа, заданного первым элементом выражения. Выражение явного
преобразования может содержать пустой список значений. В этом случае результатом
выполнения подобной операции также оказывается значение (неважно какое) заданного
простого типа. Здесь важен именно тип значения. Само же значение зависит от разных
обстоятельств. Оно вообще может оказаться неопределённым, а может определяться в
ходе выполнения программы.
Следующие две БНФ представляют схемы выражений доступа к члену класса. Они будут
рассмотрены позже.
Наконец, последняя пара БНФ представляет постфиксные выражения увеличения и
уменьшения. Эти выражения представляют собой сочетания символов (именно символов!)
операций с выражениями-операндами. Операнды выражений инкремента и декремента
обязаны быть модифицируемым l-выражениями.
Первичное выражение
Выражение строится на основе операций, объединяющих операнды. Основным элементом
выражения является первичное выражение. Первичное выражение - это фактически
элементарный строительный блок любого выражения. Следующее множество БНФ
определяет синтаксис первичного выражения:
ПервичноеВыражение ::=
::=
::=
::=
::=
::=
::=
Литерал
Имя
(Выражение)
this
::ИмяОператорнойФункции
::КвалифицированноеИмя
::Идентификатор
Понятие литерала ранее уже обсуждалось.
Нетерминальный символ Имя также определяется с помощью соответствующего
множества БНФ:
Имя ::=
::=
::=
::=
::=
Идентификатор
ИмяОператорнойФункции
ИмяФункцииПриведения
КвалифицированноеИмя
~ИмяКласса
Таким образом, квалифицированное имя является одним из вариантов имени. Оба
нетерминальных символа, в свою очередь, представляют первичные выражения.
В C++ не существует выражений без типа и значения. Даже в том случае, когда говорят,
что значение выражения не определено, выражение всё же имеет значение
соответствующего типа. Это случайное значение.
Понятие имени операторной функции связано с так называемым совместным
использованием операций (разные типы данных совместно используют одни и те же
символы операций). Совместно используемые операции в C++ служат для обозначения
особой категории функций, предназначенных для имитации операций C++.
Имя функции приведения и имя класса, которому предшествует специальный символ ~, а
также квалифицированное имя непосредственно связаны с понятием класса.
Сложность первичного выражения ничем не ограничивается. Заключённое в круглые
скобки выражение рассматривается как первичное выражение.
Первичное выражение this связано с понятием класса. Оно также имеет собственный тип и
значение, в качестве которого выступает указатель на объект.
Операция разрешения области видимости ::, за которой следует идентификатор,
квалифицированное имя или имя операторной функции, также образуют первичное
выражение.
Ничего нельзя сказать о том, что находится вне области видимости. Для транслятора C++
это потусторонний мир. И поэтому не случайно в соответствующей форме Бэкуса-Наура
после операции разрешения области видимости используется терминальный символ
Идентификатор, а не Имя. Идентификатор становится именем лишь после
соответствующего объявления. В момент выполнения операции разрешения области
видимости нельзя утверждать, что её операнд является именем.
Уже из определения первичного выражения видно, что в C++ сложность выражения
ничем не ограничивается. Вместе с тем любое правильно построенное выражение может
быть успешно распознано и систематизировано. Здесь всё зависит от контекста, а
фактически от символа "соединяющей" операнды операции.
Константные выражения
КонстантноеВыражение ::= УсловноеВыражение
В ряде случаев C++ требует, чтобы вычисляемое значение выражения было
целочисленной константой. Это относится к границам массивов, размерам битовых полей,
значениям инициализаторов элементов перечисления. Константные выражения
представляют собой неизменяемые целочисленные значения. Они строятся на основе
литералов, элементов перечисления (о них речь впереди), проинициализированных
целочисленных констант, выражений, построенных на основе операции sizeof.
Константное выражение не меняет своего значения. Поэтому константное выражение не
может быть именем переменной или выражением, которое включает имя переменной.
Константные выражения вычисляются на стадии трансляции, а потому в константном
выражении не могут использоваться функции, объекты классов, указатели, ссылки,
операция запятая и операция присваивания.
Константное выражение может состоять из литералов, имён констант, элементов
перечисления (о них позже), может содержать символы арифметических операций,
которые связывают константные выражения.
Основное назначение константного выражения в C++ - фиксация значений ограниченного
множества значений, предназначенных для организации управленния процессом
выполнения программы, задание предопределённых характеристик объектов (например,
размер массива). Управление выполнением и характеристика размерности не требует
особой точности. Органы управленния должны быть максимально простыми, количество
элементов и длина в байтах задаются целочисленными значениями. Здесь нет проблем,
связанных с точностью вычисления, здесь достаточно значений интегрального типа.
Значение константного выражения определяется уже на стадии трансляции, поскольку
размерность массива и метка помеченного оператора в операторе выбора должны быть
известны до начала выполнения программы. А это ещё один аргумент в пользу
запрещения включения в константное выражение вызовов функций (на стадии трансляции
нет возвращаемых значений).
По этой же причине константное выражение не может быть указателем или ссылкой (о
ссылках - позже), поскольку всё, что связано с адресами, определяется лишь на этапе
выполнения программы.
Константное выражение не может содержать операцию присваивания, операции
инкрементации и декрементации.
А вот операции сравнения, арифметические операции, операция sizeof и, как ни странно,
операция запятая не вызывают возражений транслятора (транслятор и считать умеет, и
сравнивать, он и размеры определяет, а также понимает, какое значение следует
присвоить выражению, содержащему символ операции запятая).
Download