Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Введение в С++. Страуструп..doc
Скачиваний:
63
Добавлен:
02.05.2014
Размер:
3.46 Mб
Скачать

3.2 Сводка операций

Полное и подробное описание операций языка С++ дано в $$R.7. Советуем

прочитать этот раздел. Здесь же приводится краткая сводка операций и

несколько примеров. Каждая операция сопровождается одним или

несколькими характерными для нее именами и примером ее использования.

В этих примерах class_name обозначает имя класса, member - имя члена,

object - выражение, задающее объект класса, pointer - выражение, задающее

указатель, expr - просто выражение, а lvalue (адрес) - выражение,

обозначающее не являющийся константой объект. Обозначение (type) задает

имя типа в общем виде (с возможным добавлением *, () и т.д.).

Если оно указано без скобок, существуют ограничения.

Порядок применения унарных операций и операций присваивания

"справа налево", а всех остальных операций - "слева направо".

То есть, a=b=c означает a=(b=c), a+b+c означает (a+b)+c, и *p++ означает

*(p++), а не (*p)++.

____________________________________________________________

Операции С++

============================================================

:: Разрешение области видимости class_name :: member

:: Глобальное :: name

____________________________________________________________

. Выбор члена object . member

-> Выбор члена pointer -> member

[] Индексирование pointer [ expr ]

() Вызов функции expr ( expr_list )

() Структурное значение type ( expr_list )

sizeof Размер объекта sizeof expr

sizeof Размер типа sizeof ( type )

____________________________________________________________

++ Постфиксный инкремент lvalue ++

++ Префиксный инкремент ++ lvalue

-- Постфиксный декремент lvalue --

-- Префиксный декремент -- lvalue

~ Дополнение ~ expr

! Логическое НЕ ! expr

- Унарный минус - expr

+ Унарный плюс + expr

& Взятие адреса & lvalue

* Косвенность * expr

new Создание (размещение) new type

delete Уничтожение (освобождение) delete pointer

delete[] Уничтожение массива delete[] pointer

() Приведение(преобразование)типа ( type ) expr

____________________________________________________________

. * Выбор члена косвенный object . pointer-to-member

->* Выбор члена косвенный pointer -> pointer-to-member

____________________________________________________________

* Умножение expr * expr

/ Деление expr / expr

% Остаток от деления expr % expr

____________________________________________________________

+ Сложение (плюс) expr + expr

- Вычитание (минус) expr - expr

____________________________________________________________

Все операции таблицы, находящиеся между двумя ближайшими друг

к другу горизонтальными чертами,

имеют одинаковый приоритет. Приоритет операций уменьшается при

движении "сверху вниз". Например, a+b*c означает a+(b*c), так как *

имеет приоритет выше, чем +; а выражение a+b-c означает (a+b)-c,

поскольку + и - имеют одинаковый приоритет, и операции + и -

применяются "слева направо".

Э

____________________________________________________________

Операции С++ (продолжение)

============================================================

<< Сдвиг влево expr << expr

>> Сдвиг вправо expr >> expr

____________________________________________________________

< Меньше expr < expr

<= Меньше или равно expr <= expr

> Больше expr > expr

>= Больше или равно expr >= expr

____________________________________________________________

== Равно expr == expr

!= Не равно expr != expr

____________________________________________________________

& Поразрядное И expr & expr

____________________________________________________________

^ Поразрядное исключающее ИЛИ expr ^ expr

____________________________________________________________

| Поразрядное включающее ИЛИ expr | expr

____________________________________________________________

&& Логическое И expr && expr

____________________________________________________________

|| Логическое ИЛИ expr || expr

____________________________________________________________

? : Операция условия expr? expr : expr

____________________________________________________________

= Простое присваивание lvalue = expr

*= Присваивание с умножением lvalue *= expr

/= Присваивание с делением lvalue /= expr

%= Присваивание с взятием lvalue %= expr

остатка от деления

+= Присваивание со сложением lvalue += expr

-= Присваивание с вычитанием lvalue -= expr

<<= Присваивание со сдвигом влево lvalue <<= expr

>>= Присваивание со сдвигом вправо lvalue >>= expr

&= Присваивание с поразрядным И lvalue &= expr

|= Присваивание с поразрядным lvalue |= expr

включающим ИЛИ

^= Присваивание с поразрядным lvalue ^= expr

исключающим ИЛИ

____________________________________________________________

Запятая (последовательность) expr , expr

____________________________________________________________

3.2.1 Скобки

Синтаксис языка С++ перегружен скобками, и разнообразие их применений

способно сбить с толку. Они выделяют фактические параметры при

вызове функций, имена типов, задающих функции, а также служат для

разрешения конфликтов между операциями с одинаковым приоритетом.

К счастью, последнее встречается не слишком часто, поскольку приоритеты

и порядок применения операций определены так, чтобы выражения вычислялись

"естественным образом" (т.е. наиболее распространенным образом).

Например, выражение

if (i<=0 || max<i) // ...

означает следующее: "Если i меньше или равно нулю, или если max меньше i".

То есть, оно эквивалентно

if ( (i<=0) || (max<i) ) // ...

но не эквивалентно допустимому, хотя и бессмысленному выражению

if (i <= (0||max) < i) // ...

Тем не менее, если программист не уверен в указанных правилах,

следует использовать скобки, причем некоторые предпочитают для

надежности писать более длинные и менее элегантные выражения, как:

if ( (i<=0) || (max<i) ) // ...

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

забывать, что сложные выражения являются источником ошибок. Поэтому,

если у вас появится ощущение, что в этом выражении нужны скобки,

лучше разбейте его на части и введите дополнительную переменную.

Бывают случаи, когда приоритеты операций не приводят к "естественному"

порядку вычислений. Например, в выражении

if (i&mask == 0) // ловушка! & применяется после ==

не происходит маскирование i (i&mask), а затем проверка результата

на 0. Поскольку у == приоритет выше, чем у &, это выражение эквивалентно

i&(mask==0). В этом случае скобки играют важную роль:

if ((i&mask) == 0) // ...

Имеет смысл привести еще одно выражение, которое вычисляется

совсем не так, как мог бы ожидать неискушенный пользователь:

if (0 <= a <= 99) // ...

Оно допустимо, но интерпретируется как (0<=a)<=99, и результат первого

сравнения равен или 0, или 1, но не значению a (если, конечно,

a не есть 1). Проверить, попадает ли a в диапазон 0...99, можно так:

if (0<=a && a<=99) // ...

Среди новичков распространена ошибка, когда в условии вместо ==

(равно) используют = (присвоить):

if (a = 7) // ошибка: присваивание константы в условии

// ...

Она вполне объяснима, поскольку в большинстве языков "=" означает "равно".

Для транслятора не составит труда сообщать об ошибках подобного рода.

3.2.2 Порядок вычислений

Порядок вычисления подвыражений, входящих в выражение, не всегда

определен. Например:

int i = 1;

v[i] = i++;

Здесь выражение может вычисляться или как v[1]=1, или как v[2]=1.

Если нет ограничений на порядок вычисления подвыражений, то транслятор

получает возможность создавать более оптимальный код. Транслятору

следовало бы предупреждать о двусмысленных выражениях, но к сожалению

большинство из них не делает этого.

Для операций

&& || ,

гарантируется, что их левый операнд вычисляется раньше правого операнда.

Например, в выражении b=(a=2,a+1) b присвоится значение 3. Пример

операции || был дан в $$3.2.1, а пример операции && есть в $$3.3.1.

Отметим, что операция запятая отличается по смыслу от той запятой, которая

используется для разделения параметров при вызове функций. Пусть есть

выражения:

f1(v[i],i++); // два параметра

f2( (v[i],i++) ) // один параметр

Вызов функции f1 происходит с двумя параметрами: v[i] и i++, но

порядок вычисления выражений параметров неопределен. Зависимость

вычисления значений фактических параметров от порядка вычислений

- далеко не лучший стиль программирования. К тому же программа

становится непереносимой.

Вызов f2 происходит с одним параметром, являющимся выражением,

содержащим операцию запятая: (v[i], i++). Оно эквивалентно i++.

Скобки могут принудительно задать порядок вычисления. Например,

a*(b/c) может вычисляться как (a*b)/c (если только пользователь

видит в этом какое-то различие). Заметим, что для значений с плавающей

точкой результаты вычисления выражений a*(b/c) и (a*b)/ могут

различаться весьма значительно.