++aCnt; // Упс! Необходим оператор break

case 'e':

 ++eCnt; // Упс! Необходим оператор break

case 'i':

 ++iCnt; // Упс! Необходим оператор break

case 'o':

 ++oCnt; // Упс! Необходим оператор break

case 'u':

 ++uCnt;

}

Чтобы понять происходящее, предположим, что значением переменной ch является 'e'. Выполнение переходит к коду после метки case 'e', где происходит инкремент переменной eCnt. Выполнение продолжается далее через метки case, увеличивая также значения переменных iCnt, oCnt и uCnt.

Несмотря на то что оператор break и не обязателен после последней метки оператора switch, использовать его все же рекомендуется. Ведь если впоследствии оператор switch будет дополнен еще одной меткой case, отсутствие оператора break после прежней последней метки не создаст проблем.

Метка default

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

// если ch гласная, увеличить соответствующий счетчик

switch (ch) {

case 'a': case 'e': case 'i': case 'o': case 'u':

 ++vowelCnt;

 break;

default:

 ++otherCnt;

 break;

}

В этой версии, если переменная ch не содержит гласную букву, управление перейдет к метке default и увеличится значение счетчика otherCnt.

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

Метка не может быть автономной; она должна предшествовать оператору или другой метке case. Если оператор switch заканчивается разделом default, в котором не осуществляется никаких действий, за меткой default должен следовать пустой оператор или пустой блок.

Определение переменной в операторе switch

Как уже упоминалось, выполнение оператора switch способно переходить через метки case. Когда выполнение переходит к некой метке case, весь расположенный выше код оператора switch будет проигнорирован. Факт игнорирования кода поднимает интересный вопрос: что будет, если пропущенный код содержит определение переменной?

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

case true:

 // этот оператор switch недопустим, поскольку инициализацию

 // можно обойти

 string file_name; // ошибка: выполнение обходит неявно

                   // инициализированную переменную

 int ival = 0;     // ошибка: выполнение обходит неявно

                   // инициализированную переменную

 int jval;         // ok: поскольку jval не инициализирована

 break;

case false:

 // ok: jval находится в области видимости, но она не инициализирована

 jval = next_num();     // ok: присвоить значение jval

 if (file_name.empty()) // file_name находится в области видимости, но

                        // она не инициализирована

 // ...

Если бы этот код был допустим, то любой переход к случаю false обходил бы инициализацию переменных file_name и ival, но они оставались бы в области видимости и код вполне мог бы использовать их. Однако эти переменные не были бы инициализированы. В результате язык не позволяет перепрыгивать через инициализацию, если инициализированная переменная находится в области видимости в пункте, к которому переходит управление.

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

case true:

 {

  // ok: оператор объявления в пределах операторного блока

  string file_name = get_file_name();

  // ...

 }

 break;

case false:

 if (file_name.empty()) // ошибка: file_name вне области видимости

Упражнения раздела 5.3.2
Перейти на страницу:

Похожие книги