C++-manual
Förutgående | Kapitel 6. Flödeskontroll | Nästa

# `switch`-uttryck

C++ har en konstruktion som är mycket praktisk då man vill välja en av flera olika alternativ. Om vi t.ex. har en meny där användaren kan välja alternativen 1, 2, 3 eller 4 kan vi implemntera det hela som en som `if`-konstruktion, men det är ganska klumpigt och väldigt fult. Istället kan man använda `switch`-uttryck. Ett exempel illustrerar vad det är frågan om:

    // läs ett menyval från tangentbordet
    char Menyval;
    cin >> Menyval;
    switch ( Menyval ) {
      case '1' : cout << "1 valdes" << endl; break;
      case '2' : cout << "2 valdes" << endl; break;
      case '3' : cout << "3 valdes" << endl; break;
      case '4' : cout << "4 valdes" << endl; break;
    }

Ovan har vi först en sats med nyckelordet `switch` som börjar `switch`-blocket. Denna tar som argument ett uttryck som skall evelueras till ett heltal. Observera att det skall vara ett heltal, inte ett boolskt uttryck som i `if`-satser. På bas av detta heltal kontrolleras varje `case`-sats för att se ifall värdet är samma. Om så är utförs `case`-satsens kropp. Så fortsätter evalueringen nedåt i `switch`-konstruktionen ända till slutet nåtts utan 'träffar', eller en eller flera `case`-satser utförts. Observera att syntaxen där ett tecken sätts innanför '' ju ger tecknets ASCII-värde, d.v.s. ett tal. Den allmänna formen för en `case`-konstruktion är:

    switch ( evaluering ) {
      case värde1 : sats1;
      case värde2 : sats2;
      ...
      case värdeN : satsN;
      default: sats;
    }

Värdena värde1 till värdeN måste vara distinkta, d.v.s. inga kopior tillåts förekomma. Den sista satsen `default` utförs normalt om ingen av de ovanstående `case`-satserna utfördes, och fungerar som en form av uppsamlare för alla värden som inte testats. Man kan se på `default` som den sista `else`-delen i en konstruktion med många `if`-satser.

Koden i en `case`-kropp är execpetionell på det viset att man inte där behöver gruppera koden i block. Satser utförs nedåt ända tills slutet av `switch`-konstruktionen nåtts, eller en `break` påträffats. Så följande exempel fungerar helt korrekt:

    char Menyval;
    cin >> Menyval;
    switch ( Menyval ) {
      case '1' : cout << "1 valdes" << endl;
                 Index++;
                 cout << "Index är nu " << Index << endl;
                 break;
      case '2' : ...
      ...
    }

Här kommer alla satser att utföras om `Menyval == '1'`. Låter det ologiskt kanske? Varför måste inte `switch` ha en blockkonstruktion när allting annat måste ha det? Svaret är att `switch` använder sig av en ganska praktisk funktionalitet som kallas fall through. Det betyder att så fort som en `case`-test är sann kommer dess sats(er) att utföras. Exekveringen kommer dock efter att `case`-kroppen utförts att direkt fortsätta med kroppen för nästa `case`-sats, d.v.s. exekveringen "faller igenom". För att stoppa detta fenomen kan man använda sig av `break`. Denna stoppar exekveringen av `switch`-konstruktionen direkt och fortsätter på satsen efter själv `switch`-blocket. Ett exempel då fall-through är praktiskt är då man vill göra en liten meny som accepterar både versaler och gemener (stora och små bokstäver). Istället för att duplicera koden för båda fallen låter man den ena falla igenom:

    char Menyval;
    cin >> Menyval;
    switch ( Menyval ) {
      case 'S' :
      case 's' : // spara en fil
                 break;
      case 'l' :
      case 'L' : // ladda in en fil
                 break;
      case 'q' :
      case 'Q' : // avsluta
                 break;
      ...
      default : // felaktigt val!
                cout << "Felaktigt val!" << endl;
    }

Här utnyttjas fall through på ett effektivt (och vackert!) sätt. I de flesta fall vill man dock inte ha denna effekt, så glöm inte bort att sätta en `break` där du inte vill ha fall through! Sist i konstruktionen ovan finns en `default`. Denna samlar upp alla värden på `Menyval` som inte matchades av någon `case`-sats. I vårt exempel har användaren då gett in ett menyval som inte kändes igen. Eftersom `break` används på alla ställen i de övriga `case`-satserna kan vi vara säkra på att alla giltiga val fångats upp och behandlats.

Förutgående | Hem | Nästa
Logiska operatorer | Upp | `? :`-operatorn