Para que serve o switch
Um switch compara um valor contra uma lista de opções fixas e executa o ramo que corresponde. Quando você se pega escrevendo uma longa cadeia de if/else if que continua testando a mesma variável contra constantes diferentes, um switch expressa essa intenção com mais clareza, e muitas vezes compila para uma tabela de saltos mais rápida.
Ele só faz verificações de igualdade contra constantes de tempo de compilação sobre um valor do tipo inteiro. Não consegue testar faixas, comparar strings nem combinar condições. Para qualquer um desses casos, continue com if/else.
O switch básico
Você fornece um valor ao switch e então lista os rótulos case para os valores que lhe interessam. Cada ramo termina com break:
O valor 3 corresponde a case 3:, então "Wednesday" é impresso e o break salta para fora do switch. O ramo default é o caso geral: ele roda quando nenhum case corresponde. É opcional, mas inclua-o a menos que você tenha certeza de que todos os valores estão tratados.
Note que os rótulos case são constantes simples seguidas de dois-pontos, não condições. Você escreve case 3:, nunca case day == 3:.
break e fall-through
Esta é a armadilha mais importante do switch em C++. Depois que um case corresponde, a execução não para no próximo case: ela continua correndo direto até encontrar um break ou a chave de fechamento. Veja o que acontece quando as instruções break estão faltando:
Você poderia esperar apenas "one". Em vez disso, as quatro linhas são impressas: ao corresponder a case 1:, entra-se no switch ali e então cai através de todos os rótulos abaixo dele. Adicione um break; depois de cada ramo e você obterá a única linha que queria. Esquecer um break é a fonte clássica dos bugs do tipo "por que meu switch está executando código demais?".
Fall-through intencional para agrupar cases
O fall-through nem sempre é um erro: é a forma idiomática de fazer vários cases compartilharem um mesmo corpo. Deixe os cases vazios (sem instruções, sem break) e todos fluem para o próximo bloco:
'A', 'B' e 'C' aterrissam todos na mesma linha "Pass" porque os dois primeiros cases estão vazios e caem através até o terceiro. Isso é limpo e intencional. Quando você realmente pretende cair através depois de rodar algum código, documente isso com um comentário, ou, em C++17 e versões posteriores, com o atributo [[fallthrough]];, que diz ao compilador "sim, isso foi de propósito" e silencia os avisos de fall-through.
switch com enums
O switch combina naturalmente com os enums, já que um enum é exatamente "um de um conjunto fixo de valores". Os compiladores também podem avisar se você esquecer de tratar um dos enumeradores:
Com um enum class com escopo, você precisa qualificar cada rótulo (Direction::East). Como todos os enumeradores estão cobertos, não é preciso default, e muitos compiladores avisarão se você adicionar uma quinta direção mais tarde e esquecer de adicionar o case dela. Essa ajuda do compilador é uma grande razão para preferir switch em vez de cadeias de if/else com enums.
Uma armadilha: declarações dentro de um case
Você não pode declarar uma variável com inicializador em um case e fazê-la ficar visível nos outros cases sem dar a ela um escopo próprio. Este é um erro de compilação comum:
switch (x) {
case 1:
int n = 10; // erro: o salto para case 2 ignora esta inicialização
cout << n;
break;
case 2:
cout << "two";
break;
}
O compilador rejeita isso porque cair dentro de case 2: saltaria por cima da inicialização de n enquanto n ainda está no escopo. A correção é envolver o corpo do case em suas próprias chaves, dando à variável um bloco só dela:
Sempre que um case precisar de sua própria variável local, dê a ele chaves. Isso também impede que a variável vaze para os cases abaixo dele.
Próximo: laço for
switch e if permitem que seu programa escolha qual código rodar uma vez. Mas muito trabalho significa fazer a mesma coisa várias vezes: contar, percorrer uma lista, repetir até que uma condição mude. O laço for é o cavalo de batalha para isso, e é a próxima página.
Perguntas frequentes
Quando devo usar switch em vez de if-else em C++?
Use switch quando estiver comparando um único valor do tipo inteiro contra muitas opções fixas e constantes, como uma escolha de menu, um número de dia ou um enum. Ele fica mais legível do que uma longa escada de if/else if e permite que o compilador otimize o desvio. Fique com if/else quando suas condições envolvem faixas (x > 10), valores de ponto flutuante, strings ou várias variáveis: o switch não consegue fazer nada disso.
Por que preciso de break em uma instrução switch do C++?
Assim que um case corresponde, o C++ continua executando os cases seguintes até encontrar um break ou o fim do switch. Isso é chamado de fall-through. O break interrompe esse fluxo. Esquecer o break é um erro clássico: você corresponde a case 1: e, por acidente, também executa o código de case 2, case 3 e do default.
Sobre quais tipos é possível usar switch em C++?
Apenas tipos integrais ou de enumeração: int, char, short, long, bool, enum com ou sem escopo, e qualquer coisa que se converta em um deles. Você não pode usar switch em um double, float ou std::string: para isso, use if/else. Cada rótulo case deve ser uma constante de tempo de compilação.