Tutorials Logic, IN info@tutorialslogic.com

C++ Conditions with if, else, switch, and Guard Clauses

Conditions Select a Path

A condition chooses which statement runs next. C++ contextually converts an if condition to bool, tests an else-if chain from top to bottom, and executes only the first matching branch.

Use if for ranges and compound predicates, guard clauses for invalid or exceptional paths, and switch for one integral or enumeration value with discrete cases. Make every boundary and fallthrough decision visible.

Condition Evaluation

The expression inside if must be usable as a Boolean condition. Comparisons produce bool directly, while numeric and pointer values can also be contextually converted: zero and null are false, and nonzero values and non-null pointers are true.

Prefer an explicit comparison when it communicates intent. if (count > 0) explains a quantity rule more clearly than relying on the truthiness of count, while if (pointer) is a familiar null check.

Construct Best fit Important rule
if One predicate or independent decision Runs its body only when the condition is true.
else if Ordered, mutually exclusive alternatives Stops after the first true branch.
else Fallback for every unmatched value Has no condition and belongs to the nearest unmatched if.
guard clause Invalid input or exceptional path Returns, continues, or throws early so the normal path stays shallow.
switch One integral or enum value with named cases Case labels are constant values; exit or fallthrough must be intentional.

If and Else Chains

An if-else-if chain is evaluated in source order. Put invalid input first, then arrange overlapping ranges from most specific to broadest so an earlier branch does not hide a later one.

Use braces even for a one-line body when the branch may grow. Braces prevent a later edit from creating a misleading indentation or dangling-else bug.

  • Use == for comparison; a single = performs assignment.
  • Test the exact values on both sides of every boundary.
  • Name a complicated condition when the name explains the business rule better than punctuation.

Ordered Age Classification

Ordered Age Classification
#include <iostream>
#include <string_view>

std::string_view category(int age) {
    if (age < 0) {
        return "invalid";
    } else if (age < 13) {
        return "child";
    } else if (age < 18) {
        return "teen";
    } else {
        return "adult";
    }
}

int main() {
    std::cout << category(-1) << "\n";
    std::cout << category(12) << "\n";
    std::cout << category(13) << "\n";
    std::cout << category(18) << "\n";
}
Output
invalid
child
teen
adult

The first matching branch wins. Testing -1, 12, 13, and 18 proves the invalid boundary and every transition between adjacent ranges.

Logical Conditions

Combine predicates with && for AND, || for OR, and ! for NOT. The && and || operators short-circuit from left to right: C++ skips the right operand when the left operand already determines the result.

Put the safety check before the operation it protects. This is useful for pointer access, divisors, indexes, and operations that should run only after validation. Avoid hiding unrelated side effects inside a condition.

Short-circuit Pointer Check

Short-circuit Pointer Check
#include <iostream>
#include <string>

struct User {
    bool active;
    std::string role;
};

bool mayConfigure(const User* user) {
    return user != nullptr
        && user->active
        && user->role == "admin";
}

int main() {
    User admin{true, "admin"};
    User viewer{true, "viewer"};

    std::cout << std::boolalpha;
    std::cout << mayConfigure(nullptr) << "\n";
    std::cout << mayConfigure(&admin) << "\n";
    std::cout << mayConfigure(&viewer) << "\n";
}
Output
false
true
false

When user is null, && stops immediately, so the program never evaluates user->active and does not dereference a null pointer.

Guard Clauses

A guard clause handles a condition that prevents normal work from continuing. Returning early reduces nesting and lets the remainder of the function describe the successful path.

A guard should state one clear reason to stop. Do not scatter partially completed state changes before validation; validate first or use an operation with a clear rollback boundary.

Validate Before Updating State

Validate Before Updating State
#include <iostream>

bool withdraw(int& balance, int amount) {
    if (amount <= 0) {
        return false;
    }
    if (amount > balance) {
        return false;
    }

    balance -= amount;
    return true;
}

int main() {
    int balance = 500;

    std::cout << std::boolalpha;
    std::cout << withdraw(balance, -20) << "\n";
    std::cout << withdraw(balance, 200) << "\n";
    std::cout << balance << "\n";
}
Output
false
true
300

Both failure paths return before balance changes. The successful path has no extra else block and performs the mutation only after validation.

Switch Statements

switch compares one integral or enumeration value against constant case labels. It cannot directly express ranges, compound predicates, or std::string comparisons, so those decisions belong in an if chain or a prior conversion step.

A matching case continues into later cases until control exits. Use break, return, or throw for an independent case; stack labels when several values share behavior; and use [[fallthrough]] when execution must deliberately continue into the next case.

Switch feature Rule
case label Must be a unique constant expression compatible with the switch value.
break Exits the switch; omitting it permits fallthrough.
return or throw Exits the function or transfers control, so break is unnecessary.
default Handles values not matched by a case; consider omitting it for a closed enum when compiler warnings should reveal missing enumerators.
initialization statement Modern C++ permits setup before the condition, such as switch (auto code = read(); code). The name is scoped to the switch.

Switch on an Enum Class

Switch on an Enum Class
#include <iostream>
#include <string_view>

enum class TrafficLight {
    red,
    yellow,
    green
};

std::string_view action(TrafficLight light) {
    switch (light) {
        case TrafficLight::red:
            return "stop";
        case TrafficLight::yellow:
            return "prepare";
        case TrafficLight::green:
            return "go";
    }

    return "unknown";
}

int main() {
    std::cout << action(TrafficLight::red) << "\n";
    std::cout << action(TrafficLight::green) << "\n";
}
Output
stop
go

Each enumerator has one visible outcome and returns directly, so accidental fallthrough is impossible. Enabling compiler warnings helps reveal a newly added enumerator that the switch does not yet handle.

Choosing a Branch

Choose the construct that makes the decision easiest to verify. Readability comes from visible boundaries and one clear selection rule, not from minimizing line count.

Decision shape Prefer Reason
Range, string, pointer, or compound predicate if / else if Conditions can use relational and logical operators.
Invalid input before normal work guard clause Failure exits early and reduces nesting.
One enum or integral value with discrete labels switch Cases make the finite alternatives easy to scan.
Choose one of two simple values conditional operator ?: Useful inside an expression when both alternatives remain short and readable.
Map many values to data table or associative container Data-driven lookup may be clearer than a long branch chain.
Verify each decision

Branch Review

6 checks
  • Every range has explicit, tested boundary values.
  • Else-if branches are ordered so a broad condition cannot hide a specific one.
  • Safety checks appear before the short-circuited expression they protect.
  • Guard clauses finish validation before state is changed.
  • Every switch case exits or documents intentional fallthrough.
  • The selected construct matches the shape of the decision.

Check Branch Reasoning

0 of 3 checked

Q1. Which else-if branch runs when more than one condition is true?

Q2. Why is pointer != nullptr placed before pointer->member in an && expression?

Q3. Which decision is a poor fit for switch?

Branch Failures

  • Assignment replaces comparison

    Write == when comparing values and enable compiler warnings. If assignment is intentional, isolate it and make the condition explicit.
  • Range branch is unreachable

    Order overlapping thresholds from most specific to broadest and test values immediately below, at, and above every boundary.
  • Switch falls into the next case

    End an independent case with break, return, or throw. Use [[fallthrough]] only when continuing is deliberate.
  • Else binds to the wrong if

    Use braces around nested branches. In C++, else belongs to the nearest unmatched if regardless of indentation.

Apply the selection rules

Practice Branch Design

0 of 3 completed

  1. Write a function that rejects negative weight, gives free shipping at zero, and selects three increasing price bands. Test every boundary. Handle invalid input first, then order the valid ranges from smallest to largest or largest to smallest without overlap.
  2. Create an enum class for add, remove, list, and quit commands. Return one message for every enumerator without accidental fallthrough. Compile with warnings, then add a new enumerator and observe how the compiler helps locate the incomplete switch.
  3. Use short-circuit evaluation to check a pointer and a nonzero divisor before reading the pointed value and dividing. Place checks from safest and cheapest to the operation that depends on them.

Condition Questions

Cases fall through unless control exits with <code>break</code>, <code>return</code>, <code>throw</code>, or another jump. Add an exit for independent cases and use <code>[[fallthrough]]</code> when continuing is intentional.

Without braces, <code>else</code> belongs to the nearest unmatched <code>if</code>, regardless of indentation. Braces make the intended ownership explicit and safer to edit.

<code>switch</code> handles integral or enum values using constant equality-style labels. It cannot directly express ranges, compound predicates, or string comparisons.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.