Урок 65. Оператор switch

   ⁄ 

 Обновлено 24 Июн 2017

  ⁄   

Хоть мы и можем использовать сразу несколько операторов if-else вместе – читается и смотрится это не очень. Например:

Использование множества if-else для проверки одной переменной – практика распространенная, но C++ предоставляет альтернативный и более эффективный условный оператор ветвления, называемый switch. Вот та же программа, но уже с использованием switch:

Общая идея операторов switch проста: выражение switch должно производить значение, а каждый случай (case) проверяет это значение на равенство. Если case совпадает с выражением switch, то выполняются инструкции после строки case. Если case не соответствует выражению switch, то выполняются инструкции после случая default (если он вообще указан).

Из-за своей реализации, операторы switch обычно более эффективны, чем цепочки if-else.

Давайте рассмотрим это более подробно.

Начало switch

Вначале используется ключевое слово switch, за которым следует выражение, с которым мы хотим работать. Обычно это выражение представляет собой только одну переменную, но это может быть и нечто более сложное, например nX + 2 или nX − nY. Единственное ограничение к этому выражение — оно должно быть интегрального типа (т. е. char, short, int, long, long long или enum). Переменные типа с плавающей запятой или не интегральные типы использоваться не могут.

После выражения switch мы объявляем блок. Внутри блока мы используем labels для определения всех значений, которые мы хотим проверять на соответствие с выражением. Существует два типа лейблов.

Лейблы case

Первый вид лейбла — это case (кейс), который объявляется с использованием ключевого слова case и имеет константное выражение. Константное выражение — это то, которое производит константное значение — другими словами: либо литерал (например, 5), либо перечисление (например, COLOR_RED), либо константу (например, переменная x, которая была объявлена как const int).

Константное выражение, находящееся после ключевого слова case проверяется на равенство с выражением, находящимся после ключевого слова switch. Если они совпадают, то тогда выполняется код после строки case.

Стоит отметить, что все выражения case должны производить уникальные значения. То есть вы не сможете сделать так:

Можно использовать сразу несколько кейсов для одного выражения. Следующая функция использует несколько случаев для проверки, является ли параметр «p» цифрой ASCII.

В случае, если «p» будет цифрой ASCII, то выполнится первый стейтмент после case: return true.

Case default (лейбл по умолчанию)

Второй тип лейбла — это лейбл по умолчанию (или просто default case), который объявляется с использованием ключевого слова default. Код под этим лейблом выполняется, если ни один из кейсов не соответствует выражению switch. Лейбл по умолчанию является необязательным. В одном switch-е может быть только один default. Обычно его объявляют последним в блоке switch.

В примере выше, если «p» не является цифрой ASCII, то тогда выполняется лейбл по умолчанию и возвращается false.

Выполнение switch и fall-through

Одна из самых каверзных вещей в switch и case — это последовательность выполнения кода. Когда case совпал (или выполняется default), то выполнение начинается с первого стейтмента, который находится после соответствующего кейса и продолжается до тех пор, пока не будет выполнено одно из следующих условий завершения:

 Достигнут конец блока switch.

 Выполняется оператор return.

 Выполняется оператор goto.

 Выполняется оператор break.

Обратите внимание, если ни одного из этих условий завершения не будет, то тогда будут выполняться все кейсы после того кейса, который совпал с выражением switch. Например:

Результат:

2
3
4
5

А это уже не то, что мы хотели! Когда выполнение переходит из одного кейса в следующий, то это называется fall-through. Программисты почти никогда не используют fall-through, поэтому в редких случаях, когда это все-таки используется — программист оставляет комментарий, в котором сообщает, что fall-through является преднамеренным.

Оператор break

Оператор break (объявленный с использованием ключевого слова break) сообщает компилятору, что мы уже сделали всё, что хотели с этим switch (или while, или do while, или for loop) и больше не намерены с ним работать. Когда компилятор встречает оператор break, то выполнение кода переходит из switch-а на следующую строку после блока switch.

Рассмотрим пример выше, но уже с корректно вставленными операторами break:

Теперь, когда подошел case 2 – выведется целое число 2, и оператор break приведет к завершению работы switch. Остальные кейсы пропускаются.

Предупреждение: Не забывайте использовать оператор break в конце каждого кейса. Его отсутствие — одна из наиболее распространенных ошибок в C++!

Несколько стейтментов внутри блока switch

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

Объявление переменной и инициализация внутри case

Вы можете объявлять, но не инициализировать переменные внутри блока case:

Обратите внимание, что хотя переменная z была определена в кейсе 1, она также используется в кейсе 2. Все кейсы считаются частью одной и той же области видимости, поэтому объявив переменную в одном кейсе, мы можем использовать её без объявления и в других кейсах.

Это может показаться немного нелогичным, поэтому давайте разберемся детальнее. Когда мы определяем локальную переменную типа «int y;», то переменная не создается в этой точке — она ​​фактически создается в начале блока, в котором объявлена. Однако она не видна в программе до своей точки объявления. Само объявление не выполняется – оно просто сообщает компилятору, что переменная уже может использоваться в коде. Поэтому, зная вышесказанное, уже не так странно, что переменная, объявленная в одном кейсе, может использоваться в другом, даже если кейс, объявляющий переменную, никогда не выполняется.

Однако инициализация переменных непосредственно в case запрещена и вызовет ошибку компиляции. Это связано с тем, что инициализация переменной требует выполнения, а case, содержащий инициализацию, может никогда не выполниться!

Если в case нужно объявить и/или инициализировать новую переменную, то это лучше всего сделать, используя блок стейтментов внутри case:

Правило: Если нужно инициализировать и/или объявить переменные внутри case – используйте блоки стейтментов.

Тест

1. Напишите функцию calculate(), которая принимает две переменные типа int и одну переменную типа char, которая представляет одну из следующих математических операций: +, -, *, / или % (модуль). Используйте switch для выполнения соответствующей математической операции над целыми числами и возвратите результат. Если в функцию передается недействительный (какой-то левый) оператор, то функция должна выводить ошибку. Для оператора деления выполняйте целочисленное деление.

2. Определите перечисление (или класс enum, если используете компилятор совместимый с C++ 11) Animal, которое содержит следующие животные: pig, chicken, goat, cat, dog и ostrich. Напишите функцию getAnimalName(), которая принимает параметр Animal и использует switch, чтобы вернуть имя этого животного как std::string. Напишите еще одну функцию — printNumberOfLegs(), которая использует switch для вывода количества лап, которое имеет каждое животное. Убедитесь, что обе функции имеют кейс default, который выводит сообщение об ошибке. Вызовите printNumberOfLegs() в main(), используя в качестве параметров cat и chicken. Ваш результат должен выглядеть следующим образом:

A cat has 4 legs.
A chicken has 2 legs.

Ответы

Ответ 1

Ответ 2

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (6 оценок, среднее: 5,00 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *