Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
86
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

С++ для начинающих

167

bitset<32> bitvec8 = bitvec2 | bitvec3;

Здесь bitvec8 инициализируется результатом побитового ИЛИ векторов bitvec2 и bitvec3. Точно так же поддерживаются и составные операции присваивания и сдвига.

Упражнение 4.15

Допущены ли ошибки в приведенных определениях битовых векторов?

(a)bitset<64> bitvec(32);

(b)bitset<32> bv( 1010101 );

(c)string bstr; cin >> bstr; bitset<8>bv( bstr );

(d)bitset<32> bv; bitset<16> bvl6( bv );

Упражнение 4.16

extern void bitstring(const char*); bool bit_on (unsigned long, int); bitset<32> bitvec;

(a)bitsting( bitvec.to_string().c_str() );

(b)if ( bit_on( bitvec.to_1ong(), 64 )) ...

Допущены ли ошибки в следующих операциях с битовыми векторами?

(c) bitvec.f1ip( bitvec.count() );

Упражнение 4.17

Дана последовательность: 1,2,3,5,8,13,21. Каким образом можно инициализировать объект bitset<32> для ее представления? Как присвоить значения для представления этой последовательности пустому битовому вектору? Напишите вариант инициализации и вариант с присваиванием значения каждому биту.

4.13. Приоритеты

Приоритеты операций задают последовательность вычислений в сложном выражении. Например, какое значение получит ival?

int ival = 6 + 3 * 4 / 2 + 2;

Если вычислять операции слева направо, получится 20. Среди других возможных результатов будут 9, 14 и 36. Правильный ответ: 14.

В С++ умножение и деление имеют более высокий приоритет, чем сложение, поэтому они будут вычислены раньше. Их собственные приоритеты равны, поэтому умножение и деление будут вычисляться слева направо. Таким образом, порядок вычисления данного выражения таков:

1.3 * 4 => 12

2.12 / 2 => 6

3.6 + 6 => 12

4.12 + 2 => 14

С++ для начинающих

168

Следующая конструкция ведет себя не так, как можно было бы ожидать. Приоритет операции присваивания меньше, чем операции сравнения:

while ( ch = nextChar() != '\n' )

Программист хотел присвоить переменной ch значение, а затем проверить, равно ли оно символу новой строки. Однако на самом деле выражение сначала сравнивает значение, полученное от nextChar(), с '\n', и результат true или false присваивает переменной ch.

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

4

* 5

+

7 * 2

==>

34

4

* ( 5

+ 7 *

2

)

==> 76

4

* (

(5 + 7)

*

2

) ==> 96

Вот как с помощью скобок исправить поведение предыдущего примера:

while ( (ch = nextChar()) != '\n' )

Операторы обладают и приоритетом, и ассоциативностью. Оператор присваивания правоассоциативен, поэтому вычисляется справа налево:

ival = jval = kva1 = lval

Сначала kval получает значение lval, затем jval значение результата этого присваивания, и в конце концов ival получает значение jval.

Арифметические операции, наоборот, левоассоциативны. Следовательно, в выражении

ival + jval + kva1 + 1va1

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

В таблице 4.4 приведен полный список операторов С++ в порядке уменьшения их приоритета. Операторы внутри одной секции таблицы имеют равные приоритеты. Все операторы некоторой секции имеют более высокий приоритет, чем операторы из секций, следующих за ней. Так, операции умножения и деления имеют одинаковый приоритет, и он выше приоритета любой из операций сравнения.

Упражнение 4.18

(a)! ptr == ptr->next

(b)~ uc ^ 0377 & ui << 4

Каков порядок вычисления следующих выражений? При ответе используйте таблицу 4.4.

(c) ch = buf[ bp++ ] != '\n'

Упражнение 4.19

С++ для начинающих

169

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

Упражнение 4.20 Следующие выражения вызывают ошибку компиляции из-за неправильно понятого

(a) int i = doSomething(), 0;

приоритета операций. Объясните, как их исправить, используя таблицу 4.4.

(b) cout << ival % 2 ? "odd" : "even";

Таблица 4.4. Приоритеты операций

Оператор

Значение

 

 

Использование

 

 

 

 

 

::

Глобальная

область

::name

 

видимости

 

 

 

 

::

Область

видимости

class::name

 

класса

 

 

 

 

::

Область

видимости

namespace::name

 

пространства имен

 

 

 

.

Доступ к члену

 

object.member

->

Доступ к

члену

по

pointer->member

 

указателю

 

 

 

 

[]

Взятие индекса

 

variable[expr]

()

Вызов функции

 

name(expr_list)

()

Построение значения

type(expr_list)

++

постфиксный инкремент

lvalue++

 

--

постфиксный декремент

lvalue--

 

typeid

идентификатор типа

typeid(type)

 

typeid

идентификатор

типа

typeid(expr)

 

 

выражения

 

 

 

 

const_cast

преобразование типа

const_cast<type>(expr)

 

dynamic_cast

преобразование типа

dynamic_cast<type>(expr)

 

reinterpret_cast

приведение типа

 

reinterpret_cast<type>

 

 

 

 

 

(expr)

 

static_cast

приведение типа

 

static_cast<type>(expr)

 

sizeof

размер объекта

 

sizeof expr

 

sizeof

размер типа

 

 

sizeof( type)

 

++

префиксный инкремент

++lvalue

 

--

префиксный декремент

--lvalue

 

С++ для начинающих

 

 

 

 

 

170

 

 

 

 

 

 

 

~

побитовое НЕ

 

 

~expr

 

 

!

логическое НЕ

 

 

!expr

 

 

-

унарный минус

 

 

-expr

 

 

+

унарный плюс

 

 

+expr

 

 

*

разыменование

 

 

*expr

 

 

&

адрес

 

 

 

&expr

 

 

()

приведение типа

 

 

(type)expr

 

 

new

выделение памяти

 

new type

 

 

new

выделение

памяти

и

new type(exprlist)

 

 

инициализация

 

 

 

 

 

new

выделение памяти

 

new

(exprlist)

 

 

 

 

 

 

type(exprlist)

 

 

new

выделение

памяти под

все формы

 

 

 

массив

 

 

 

 

 

 

delete

освобождение памяти

 

все формы

 

 

delete

освобождение

памяти

все формы

 

 

 

из-под массива

 

 

 

 

 

->*

доступ к

члену

классу

pointer->

 

 

 

по указателю

 

 

*pointer_to_member

 

.*

доступ к члену класса

object.*pointer_to_member

 

 

по указателю

 

 

 

 

 

*

умножение

 

 

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 ^ expr

 

 

 

ИСКЛЮЧАЮЩЕЕ