Team LiB   Previous Section   Next Section

4.4 Selections

A selection statement chooses one branch from multiple possibilities and executes the statements in that branch. The two selection statements supported by C++ are if and switch.

4.4.1 if Statements

An if statement has one of the following forms:

if ( condition ) statement

or:

if ( condition ) statement else statement

In the first form, the condition is converted to a bool, and if it is true, the statement is executed. Otherwise, the statement is skipped, and execution continues with the subsequent statement.

The second form chooses one of two alternative code paths. The condition is converted to a bool, and if it is true, the first statement is executed. Otherwise, the second statement is executed. Declarations in the first statement are not visible in the second. If if statements are nested, the else part binds with the closest, preceding if statement. Example 4-3 shows nested if statements.

Example 4-3. Nested if statements
if (c1)
  if (c2)
    cout << "c1 and c2 are true\n";
  else
    cout << "c1 is true, but c2 is false\n";
else if (c2)
  cout << "c1 is false, but c2 is true\n";
else
  cout << "c1 and c2 are false\n";

4.4.2 switch Statements

A switch statement chooses one execution path from among many alternatives. The syntax is:

switch ( condition ) statement

The condition must have an integral or enumerated type, or be of a class type in which the class has a single conversion function to an integral or enumerated type. The condition is evaluated once. Its value is compared against the case labels in the statement. If a case label matches the condition, execution continues with the statement immediately after the case label. If no case matches the condition, execution continues after the default label, if one is present. If there is no default label, the switch's statement is skipped and execution continues with the subsequent statement.

The statement part of a switch statement is typically a compound statement, in which every substatement has one or more case labels or a default label. The syntax for case and default labels is:

case constant-expression : statement
default : statement

The constant-expression must have an integral or enumerated type. The value is implicitly converted to the type of the condition. In a single switch statement, all case constant-expressions must have different values. A single statement in the switch's substatement can have multiple case labels, and a single switch statement can have any number of cases.

In C++, like C and Java, but unlike most other languages, a case or default label does not affect control flow. Execution continues from one case to the next, which is known as "falling through" to the next case. Use the break statement (described later in this chapter) to exit from a switch statement.

There can be at most one default case in a switch statement; it can appear anywhere in the statement. (The default case does not have to be last, as in some languages.)

By convention, case and default labels appear at the top level of the switch's substatement. They can appear in nested statements, but that makes the statements hard to read. In nested switch statements, case and default labels apply only to the innermost switch statement.

You should not define any objects in the switch's substatement unless they are enclosed in a nested compound statement. When the switch dispatches control to a particular case, it might jump over the declaration. Jumping over a declaration results in undefined behavior unless the declared object has POD type and is not initialized.

Example 4-4 shows sample switch statements.

Example 4-4. Switch statements
enum color { black, red, green, yellow, blue,
             magenta, cyan, white };
color get_pixel(unsigned r, unsigned c) { ... }

void demo(  )
{
  using std::cout;
  int r = ...
  int c = ...

  switch (get_pixel(r, c))
  {
    cout << "this is never executed, but it is valid\n";
    case black:
       cout << "no color\n";
       break; // Don't forget the break statements!
    case red: case green: case blue:
      cout << "primary\n";
      break; // Omitting break is a common mistake.
    default:
      cout << "mixed\n";
      switch (get_pixel(r+1, c+1))
      case white: {
        const int x = 0;
        cout << "  white\n"; // This case is private to the inner switch
                             // statement.
        c = x;
      }
      if (r > 0)
        // If the color is yellow, the switch branches directly to here. For
        // colors other than red, green, blue, and black, execution jumps to the
        // default label and arrives here if r > 0.
        case yellow:
         cout << " yellow or r > 0\n";

      break; // A break after the last case is not necessary, but is a good idea
             // if you add a case later.
  }
}

The outer switch statement has one case for black; another case for red, green, or blue; a default case; and a final case for yellow. The first two branches are conventional, and each ends with a break statement to exit the switch.

The case for yellow is unusual and hard to read because it is buried in an if statement. The same statement can be reached from the default case when the if condition is true (that is, r > 0).

The default case has a nested switch, which has a single case, white. The inner switch statement is atypical because it does not have a compound statement as its body.

    Team LiB   Previous Section   Next Section