Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
finalgrade = (grade > 90) ? "high pass"
: (grade < 60) ? "fail" : "pass";
Первое условие проверяет, не выше ли оценка 90. Если это так, то выполняется выражение после ?, возвращающее литерал "high pass". Если условие ложно, выполняется ветвь :, которая сама является другим условным выражением. Это условное выражение проверяет, не меньше ли оценка 60. Если это так, то обрабатывается ветвь ?, возвращающая литерал "fail". В противном случае ветвь : возвращает литерал "pass".
Условный оператор имеет правосторонний порядок, т.е. его операнды группируются (как обычно) справа налево. Порядок объясняет тот факт, что правое условное выражение, сравнивающее grade со значением 60, образует ветвь : левого условного выражения.
Вложенные условные выражения быстро становятся нечитабельными, поэтому нежелательно создавать больше двух или трех вложений.
Применение условного оператора в выражении выводаУсловный оператор имеет довольно низкий приоритет. Когда условный оператор используется в большом выражении, его, как правило, следует заключать в круглые скобки. Например, условный оператор нередко используют для отображения одного из значений в зависимости от результата проверки условия. Отсутствие круглых скобок вокруг условного оператора в выражении вывода может привести к неожиданным результатам:
cout << ((grade < 60) ? "fail" : "pass"); // выводит pass или fail
cout << (grade < 60) ? "fail" : "pass"; // выводит 1 или 0!
cout << grade < 60 ? "fail" : "pass"; // ошибка: сравнивает cout с 60
Второе выражение использует сравнение grade и 60 как операнд оператора <<. В зависимости от истинности или ложности выражения grade < 60 выводится значение 1 или 0. Оператор << возвращает объект cout, который и проверяется в условии условного оператора. Таким образом, второе выражение эквивалентно следующему:
cout << (grade < 60); // выводит 1 или 0
cout ? "fail" : "pass"; // проверяет cout, а затем возвращает один из
// этих двух литералов в зависимости от
// истинности объекта cout
Последнее выражение ошибочно, поскольку оно эквивалентно следующему:
cout << grade; // приоритет оператора ниже, чем у
// сдвига, поэтому сначала выводится оценка,
cout < 60 ? "fail" : "pass"; // затем cout сравнивается с 60!
Упражнения раздела 4.7Упражнение 4.21. Напишите программу, использующую условный оператор для поиска в векторе vector<int> элементов с нечетным значением и их удвоения.
Упражнение 4.22. Дополните программу, присваивающую переменной значение оценки (высокая, проходная, не проходная), еще одной оценки, минимально проходной, от 60 до 75 включительно. Напишите две версии: одна использует только условные операторы; вторая использует один или несколько операторов if. Как по вашему, какую версию проще понять и почему?
Упражнение 4.23. Следующее выражение не компилируется из-за приоритета операторов. Используя таблицу из раздела 4.12, объясните причину проблемы. Как ее исправить?
string s = "word";
string p1 = s + s[s.size() - 1] == 's' ? "" : "s" ;
Упражнение 4.24. Программа, различавшая проходную и непроходную оценку, зависела от того факта, что условный оператор имеет правосторонний порядок. Опишите, как обрабатывался бы этот оператор, имей он левосторонний порядок.
4.8. Побитовые операторы
Побитовые операторы (bitwise operator) получают операнды целочисленного типа, которые они используют как коллекции битов. Эти операторы позволяют проверять и устанавливать отдельные биты. Как будет описано в разделе 17.2, эти операторы можно также использовать для библиотечного типа bitset, представляющего коллекцию битов изменяемого размера.
Как обычно, если операнд — "малое целое число", его значение сначала преобразуется (раздел 4.11) в больший целочисленный тип. Операнды могут быть знаковыми или беззнаковыми.
Таблица 4.3. Побитовые операторы (левосторонний порядок)
Оператор Действие Применение ~ Побитовое NOT ~выражение << Сдвиг влево выражение1 << выражение2 >> Сдвиг вправо выражение1 >> выражение2 & Побитовое AND выражение1 & выражение2 ^ Побитовое XOR выражение1 ^ выражение2 | Побитовое OR выражение1 | выражение2Если операнд знаковый и имеет отрицательное значение, то способ обработки "знакового разряда" большинства битовых операций зависит от конкретной машины. Кроме того, результат сдвига влево, изменяющего знаковый разряд, непредсказуем.
Поскольку нет никаких гарантий однозначного выполнения побитовых операторов со знаковыми переменными на разных машинах, настоятельно рекомендуется использовать в них только беззнаковые целочисленные значения.
Побитовые операторы сдвигаМы уже использовали перегруженные версии операторов >> и <<, которые библиотека IO определяет для ввода и вывода. Однако первоначальное значение этих операторов — побитовый сдвиг операндов. Они возвращают значение, являющееся копией (возможно преобразованной) левого операнда, биты которого сдвинуты. Правый операнд не должен быть отрицательным, и его значение должно быть меньше количества битов результата. В противном случае операция имеет неопределенный результат. Биты сдвигаются влево (<<) или право (>>), при этом вышедшие за пределы биты отбрасываются.
Оператор сдвига влево (<<) (left-shift operator) добавляет нулевые биты справа. Поведение оператора сдвига вправо (>>) (right-shift operator) зависит от типа левого операнда: если он беззнаковый, то оператор добавляет слева нулевые биты; если он знаковый, то результат зависит от конкретной реализации: слева вставляются либо копии знакового разряда, либо нули.
В этих примерах подразумевается, что младший бит расположен справа, тип char содержит 8 битов, а тип int — 32 бита
// 0233 - восьмеричный литерал (см. раздел 2.1.3)
unsigned char bits = 0233; 1 0 0 1 1 0 1 1
bits << 8 // bits преобразуется в int и сдвигается влево на 8 битов
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0
bits << 31 // сдвиг влево на 31 бит отбрасывает крайние левые биты
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
bits >> 3 // сдвиг вправо на 3 бита отбрасывает 3 крайних правых бита
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1
Побитовый оператор NOTПобитовый оператор NOT (~) (bitwise NOT operator) создает новое значение с инвертированными битами своего операнда. Каждый бит, содержащий 1, превращается в 0; каждый бит, содержащий 0, — в 1.
unsigned char bits = 0227; 1 0 0 1 0 1 1 1
~bits
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0
Здесь операнд типа char сначала преобразуется в тип int. Это оставляет значение неизменным, но добавляет нулевые биты в позиции старших разрядов. Таким образом, преобразование в тип int добавляет 24 бита старших разрядов, заполненных нулями. Биты преобразованного значения инвертируются.
Побитовые операторы AND, OR и XORПобитовые операторы AND (&), OR (|) и XOR (^) создают новые значения с битовым шаблоном, состоящим из двух их операндов.
unsigned char b1 = 0145; 0 1 1 0 0 1 0 1
unsigned char b2 = 0257; 1 0 1 0 1 1 1 1
b1 & b2 Все 24 старших бита 0 0 0 1 0 0 1 0 1