Skip to content
Shafin Chowdhury
Go back

Conditional Statements in C++: if, else if, else, and switch

Software Developer & Computer Science Student

Published:
5 min read
Edit page
Table of Contents10 topics

Programs would be completely static if they could only execute commands sequentially from top to bottom. To build intelligent, adaptable software, code must make decisions: validating credentials, reacting to user inputs, or handling edge cases.

In C++, decision-making is implemented through conditional statements: the if, else if, else family and the switch statement.


What You’ll Learn

  • How the computer evaluates boolean branching conditions
  • Syntax and flow of if, else, and multi-branch else if ladders
  • Modern C++17 if statements with local initializers
  • How switch statements evaluate discrete integral values efficiently
  • Understanding break, default, and C++17 [[fallthrough]]
  • Real-world practical examples: grade evaluation, access authorization, and CLI menus
  • When to choose an if ladder vs. a switch table
  • Solving common pitfalls: the dangling else and accidental assignment in conditions

The if Statement

The if statement executes a block of code only when a specified boolean condition evaluates to true:

if (condition) {
    // Statements executed if condition is true
}

If the condition evaluates to false, the compiler skips the enclosed block and continues execution immediately following the closing brace.

int batteryLevel = 15;

if (batteryLevel < 20) {
    cout << "Warning: Battery low. Please connect charger.\n";
}

The if-else Statement

When you need to execute one branch if the condition is true, and an alternative branch if it is false, use if-else:

int age = 17;

if (age >= 18) {
    cout << "Access Granted: Adult ticket issued.\n";
} else {
    cout << "Notice: Minor passenger, parental consent required.\n";
}

Multi-Way Branching: else if Ladders

When evaluating mutually exclusive conditions that span multiple criteria or numerical ranges, chain else if clauses:

Real-World Example: Academic Grade Classification

#include <iostream>

using namespace std;

int main() {
    int score = 87;

    cout << "Exam Score: " << score << "\nClassification: ";

    if (score >= 90) {
        cout << "Grade A (Honors)\n";
    } else if (score >= 80) {
        cout << "Grade B (Above Average)\n";
    } else if (score >= 70) {
        cout << "Grade C (Average)\n";
    } else if (score >= 60) {
        cout << "Grade D (Passing)\n";
    } else {
        cout << "Grade F (Failing)\n";
    }

    return 0;
}

Output

Exam Score: 87
Classification: Grade B (Above Average)

In an else if ladder, conditions are evaluated sequentially from top to bottom. As soon as one condition evaluates to true, its corresponding block executes, and all remaining branches are skipped entirely.


Nested Conditions

Conditional statements can be nested inside other conditional blocks to test multi-layered requirements:

#include <iostream>

using namespace std;

int main() {
    int a = 45, b = 78, c = 23;
    int largest = 0;

    // Finding the largest of three numbers
    if (a >= b) {
        if (a >= c) {
            largest = a;
        } else {
            largest = c;
        }
    } else {
        if (b >= c) {
            largest = b;
        } else {
            largest = c;
        }
    }

    cout << "The largest number is: " << largest << '\n';
    return 0;
}

[!TIP] While nesting is valid, deeply nested conditions (greater than 2–3 levels) reduce code readability. Flatten nested conditions using logical operators (&&, ||) or early return guard clauses whenever possible:

if (a >= b && a >= c) {
    largest = a;
} else if (b >= a && b >= c) {
    largest = b;
} else {
    largest = c;
}

Modern C++17: if with Initializer

In C++17, C++ introduced the ability to declare and initialize a variable directly within the if statement header:

if (init-statement; condition)\mathbf{if\ (} \text{init-statement} \mathbf{;} \text{ condition} \mathbf{)}

The variable exists only within the scope of that if and its associated else blocks:

#include <iostream>

using namespace std;

int querySystemStatus() {
    return 404; // Simulated error code
}

int main() {
    // 'statusCode' is created, evaluated, and scoped strictly to this decision
    if (int statusCode = querySystemStatus(); statusCode != 200) {
        cout << "Connection failed with error code: " << statusCode << '\n';
    } else {
        cout << "System operational.\n";
    }

    // statusCode is NOT accessible here! Prevents namespace pollution.
    return 0;
}

The switch Statement

When a single variable or expression must be tested against a series of discrete constant values, the switch statement provides a cleaner and often more performant alternative to a long if-else chain.

Key Syntax and Mechanics

switch (expression) {
    case constant1:
        // Statements
        break;
    case constant2:
        // Statements
        break;
    default:
        // Statements executed if no case matches
        break;
}

Constraints on switch

  1. Integral or Enum Only: The switch expression and case values must be integral types (int, char, short, long, bool) or enumerations. You cannot switch on floating-point numbers (float, double) or strings (std::string).
  2. Compile-Time Constants: Every case label must be a constant expression evaluated at compile time.

Real-World Example: Interactive CLI Menu

#include <iostream>

using namespace std;

int main() {
    cout << "--- Terminal Server Manager ---\n";
    cout << "1. Start Service\n";
    cout << "2. Stop Service\n";
    cout << "3. Restart Service\n";
    cout << "4. Exit\n";
    cout << "Select an option (1-4): ";

    int choice = 0;
    cin >> choice;

    switch (choice) {
        case 1:
            cout << "Starting service daemon...\n";
            break;
        case 2:
            cout << "Shutting down service gracefully...\n";
            break;
        case 3:
            cout << "Restarting service...\n";
            break;
        case 4:
            cout << "Exiting manager. Goodbye.\n";
            break;
        default:
            cout << "Invalid choice! Please select 1 through 4.\n";
            break;
    }

    return 0;
}

Fallthrough Mechanics in switch

In C++, execution enters a matching case and continues executing sequentially until it hits a break statement or the end of the switch. If you omit break, execution “falls through” into subsequent cases:

Intentional Fallthrough (Grouping Cases)

Sometimes fallthrough is deliberate to share code across multiple inputs:

char keyPress = 'y';

switch (keyPress) {
    case 'y':
    case 'Y':
        cout << "Action confirmed.\n";
        break;
    case 'n':
    case 'N':
        cout << "Action cancelled.\n";
        break;
    default:
        cout << "Unrecognized key.\n";
        break;
}

Modern C++17 [[fallthrough]] Attribute

To prevent compiler warnings and document that fallthrough was intentional rather than an accidental missing break, use the [[fallthrough]] attribute:

switch (logLevel) {
    case 3: // Debug
        enableVerboseLogging();
        [[fallthrough]];
    case 2: // Info
        enableStandardLogging();
        [[fallthrough]];
    case 1: // Error only
        enableErrorLogging();
        break;
}

Comparison: if-else vs. switch

Featureif-else Ladderswitch Statement
Supported TypesAny type supporting boolean expressions (double, string, custom objects)Integral types (int, char, bool) and enum
Condition TypesRelational ranges (x > 10), complex logical formulas (a && !b)Exact equality matching against discrete compile-time constants
Branch ResolutionEvaluated sequentially (O(N)O(N) linear inspection)Often optimized by compilers into a O(1)O(1) jump table or binary tree
ReadabilityIdeal for range checks and compound logicIdeal for multi-option discrete menus, state machines, and opcode dispatch

Common Beginner Mistakes

1. Assignment in Conditions

int target = 0;
// BUG: Assigns 5 to target! Evaluates to true, loop/branch always fires!
if (target = 5) {
    cout << "Target is five\n";
}
// FIX: Always use equality comparison ==
if (target == 5) { /* ... */ }

2. Missing break in switch

Omitting break accidentally causes unwanted code from the following case to execute.

3. The Dangling else Ambiguity

In nested if statements without braces, an else binds to the closest preceding if:

// Misleading indentation:
if (isOnline)
    if (hasData)
        processData();
else
    connectToNetwork(); // Binds to 'if (hasData)', NOT 'if (isOnline)'!

Always use curly braces {} for all control flow blocks, even for single-line statements!


Best Practices

  1. Always use curly braces: Never omit braces {}. It eliminates dangling-else bugs and prevents accidental omission when lines are added later.
  2. Scope variables tightly: Use C++17 if (init; condition) to limit the visibility of variables that are only relevant to the decision.
  3. Always provide a default case in switch: Even if you believe all possible values are covered, a default case handles unexpected corrupted inputs gracefully.
  4. Prefer early returns: Instead of nesting code 5 levels deep, invert conditions and return early:
    if (!user.isValid()) return;
    if (!user.hasPermissions()) return;
    // Main logic continues cleanly...

Summary

  • The if, else if, and else statements handle conditional branching for arbitrary boolean expressions.
  • C++17 if (init; condition) scopes temporary variables directly to the conditional statement.
  • The switch statement tests discrete integral or enum values against constant case labels.
  • Omission of break causes execution to fall through into subsequent cases; use [[fallthrough]] when intentional.
  • Always use curly braces {} for every branch.

Continue Learning C++


Edit page
Share this post:

Related Articles

Continue exploring related topics and foundational concepts.


Previous Post
Loops in C++: for, while, do-while, and Range-Based Iteration
Next Post
C++ Operators: Arithmetic, Logical, Bitwise, and Precedence Explained