next up previous contents
Next: Loops Up: Getting Started in C++ Previous: Doing Things With Objects   Contents

Subsections

Make Decisions

Conditionals are special statements which execute a statement depending on a condition (like ``if you pay, you get the beer''). There are two conditionals in C++: if and switch.

if

The if statement is used just as in English:

// How 'if' works

#include <iostream>
using namespace std;

int main() {
    cout << "Enter your age: ";
    int age;
    cin >> age;

    if (age < 20)
        cout << "You are still young!\n";
}
As you can see, if the condition in the parentheses is true the following statement is executed, otherwise it isn't. But there is more to if:
// More about if

#include <iostream>
using namespace std;

int main() {
    cout << "Enter your age: ";
    int age;
    cin >> age;

    if (age < 20)
        cout << "You are still young!\n";
    else
        cout << "You are not so young anymore.\n";
}
Here the else statement was used. If the condition of the if is true, the statement after the if is executed. Otherwise, the one after the else is executed.

Compound Statements

In C++, every simple statement can be replaced by a compound statement or block. But first of all: what is a simple statement? The short answer: everything followed by a semicolon except a declaration. This is not 100% true, but good enough as a rule of thumb. A compound statement (or block) is a group of simple statements, enclosed by braces ({}). In other words, instead of a single statement after an if block you can have many ``grouped'' statements which are executed together, like here:

if (age < 20) {
    // Put as many instructions as you want here
}
else {
    // Do other things...
}

switch

The other conditional is switch. It is not as widely used as if but very useful under some circumstances. It is used to analyze a variable, compare it to a series of constants and execute the associated code, as follows:

#include <iostream>
using namespace std;

int main() {
    cout << "What would you like to do:\n";
    cout << "1. Add an entry to the address book\n";
    cout << "2. Look up an address\n";
    cout << "3. Remove an entry\n\n";
    cout << "Your choice: ";
    int selection;
    cin >> selection;

    switch (selection) {
    case 1:
        cout << "Sorry, this feature has yet to be "
             << "programmed.\n"; 
        break;

    case 2:
        cout << "Sorry, this feature was not yet "
             << "implemented.\n"; 
        break;

    case 3:
        cout << "Access denied.\n";
        break;

    default:
        cout << "You can't do that. You must choose "
             << "1, 2 or 3.\n"; 
        break;
    }
}
As you can see, one of the case statements is executed if the constant matches the variable passed to switch, and the default statement is executed if it no one matches. The default statement is optional; if there is none, and the variable doesn't match any of the constants, no one of the statements is executed.

There are some drawbacks with the switch statement, though. The first one is that the execution ``falls through'' the case clauses. This means that when the end of a case clause is reached, the program will not jump to the end of the entire switch block and continue execution after it as one would expect, but just continue in the next case clause until it reaches the end of the switch block. To avoid that, you use the break statements, which tell the compiler to jump to the end immediately. That's why it is very important never to forget the break statements. It is completely legal and correct not to use them, and under some circumstances it might be even useful; but generally you need them.

The second drawback is that only constants can be used in the case clauses. For the simple programs we are writing at this stage this is not a problem; further on you will no doubt need to compare a variable to other variables, and not constants; to do so, just use if and the == operator, which I'm just going to talk about.

There are also quite a lot of other problems with switch statements, but I'll cover them later.

The Most Important Operators

To be able to use the if statement, you need some operators. One of them (>) was already used in the example program; but there are several others you need to know about:

  1. == is the equality operator. a == b is true if a is equal to b, false if it isn't. Do not confuse this operator with the assignment operator =; a = b assigns the value of b to a.

  2. != is the opposite of ==. a != b is true if a is not equal to b, false otherwise.

  3. >, <, >=, <= are the greater, less, greater or equal to and less or equal to operators, respectively. They work just as you'd expect.

  4. && is the logical and operator. It is true if both expressions to its left and its right are true. For example, a > 10 && a < 20 is true if a is greater than 10 and less than 20 (in other words, if it is somewhere between 11 and 19). Make sure you do not confuse this with operator &.

  5. || is the logical or operator. It is true if at least one of the two expressions is true. For example, a < 10 || a > 100 is true if a is less than 10 or greater than 100. Make sure you do not confuse this with operator |.

  6. ! is the logical not operator. It negates what follows. For example, !(a > 10) is the same thing as a <= 10.

Precedence and Parentheses

There is a problem with operators though. As long as there is only one operator, like in a < 10 everything is clear. But what if you write a < 10 || a > 10 && !a >= 10 - a? Obviously it is not clear what that expression does, because it is not clear what is executed first. There ``operator precedence'' comes in. In C++ every operator has a certain precedence; operators with a higher precedence are evaluated first. As a general rule, the math operators (+, -, *, /) have a higher precedence than the comparison operators (>, <, >=, <=), and these have a higher precedence than the logical operators (\&\&, ||). You can use parentheses to influence the order in which operators are executed, like this:

if ((a > 10) || (a < -10)) {
    //...do whatever you want
}
This is the exact same thing as
if (a > 10 || a < -10) {
    //...do whatever you want
}
but it is better to use too many parentheses than too few if you are not sure.


Scope

With compound statements and the if statement it is necessary to introduce a new concept: scope.

Scope is yet another aspect of an object. It is the part of the program from where an object can be accessed. For example, in

int main() {
    int i;
}
the variable (or object, if you prefer) i has a scope which goes from the declaration to }. In other words, it can be accessed only between the declaration and the closing brace. That might not sound very sensible, because of course it would not make any sense to access it before it was declared, and you cannot put anything after the closing brace anyway. But look at this:
int main() {
    if (1 == 1) {
        int i;
        i = 3; // This is fine
    }
    
    i = 4; // This causes an error
}
The condition if(1 == 1) is of course always true because 1 is always equal to 1. But that's besides the point.

As you can see, we declare i inside the if block. This is no problem. Then we assign 3 to it. This is no problem either. But we cannot assign 4 to it later outside the if block because the scope of i goes from the declaration to the closing brace of the if block.

Opposed to that the following will work just fine, because the scope of i goes from the declaration of i to the closing brace of the main block.

int main() {
    int i;
    if (1 == 1) {
        i = 3;
    }
    i = 4;
}

It is also possible to declare (and optionally initialize) object outside any block, like this:

#include <iostream>
using namespace std;

int i = 4;

int main() {
    cout << "i = " << i << "\n";
    i = 232;
    cout << "i = " << i << "\n";
}
An object declared like this is said to have ``global scope'', or just called a ``global object'' because it is available everywhere4.1.

As every object has a scope, it is of course possible to declare objects with the same name in different scopes, like this:

#include <iostream>
using namespace std;

int main() {
    cout << "1. Calculate a sum\n";
    cout << "2. Calculate a product\n";
    cout << "Your choice: ";
    int selection;
    cin >> selection;
    
    if (selection == 1) {
        cout << "Enter the two numbers to sum "
             << "separated by a space: ";
        int first, second;
        // Notice how cin can be used to input more
        // than one value in a single call
        cin >> first >> second;
        cout << "The sum is: " << first + second 
             << "\n";
    }
    else {
        cout << "Enter the two numbers to multiply "
             << "separated by a space: "; 
        int first, second;
        cin >> first >> second;
        cout << "The product is: " << first * second 
             << "\n";
    }
}
Notice that the two objects are not the same thing. They just happen to share the same name, but they are completely independent, just as two people with the same name have two independent bodies, brains, arms, and whatever else you might think of.

Lifetime

Every object has a lifetime. The lifetime of an object starts when it is declared and ends when it goes ``out of scope''. This means that an object is created or constructed when it is declared, and it is destroyed when it goes out of scope.

int main() {
    int i; // i is created here

    if (true) {
        int j; // j is created here
    } // j is destroyed here

} // i is destroyed here
If you have understood the concept of scope, this is quite logic. When an object goes out of scope it can not be used anymore, and is thus destroyed.

Hiding

Another concept strictly linked to scope is hiding. Hiding happens when an object with the same name as another object is declared inside the scope of the first one, as follows:

#include <iostream>
using namespace std;

int main() {
    // Declare the object i.
    int i = 5;

    // This will print 5, of course.
    cout << "i = " << i << "\n";

    if (true) {
        // Now we declare *another* object i. It is
        // *not* the same i as before, but a completely
        // independent one, and it will hide the first
        // i (the one with the value 5).
        int i = 7;

        // This will print 7 because the first i (with
        // the value 5) is hidden by the second i (with
        // the value 7).
        cout << "i = " << i << "\n";

        // The scope of the second i ends here.
    }

    // This is 5 again, because we are referring to the
    // first i again.
    cout << "i = " << i << "\n";
}
It is of course not a very good idea to do so, because it is confusing and it is not possible to access the hidden object inside the scope of the hiding object. It is, though, an important concept.

Examples

Here a few a bit a longer program for your pleasure.


#include <iostream>
using namespace std;

int main() {
    // First display the menu.
    cout << "What do you want to do:\n";
    cout << "1. Calculate the area of a square\n";
    cout << "2. Calculate the area of a circle\n";
    cout << "Your choice: ";

    // Take the user's selection.
    int choice;
    cin >> choice;

    // Do the right thing based on the user's
    // selection.
    switch (choice) {
    case 1: {
        // We need braces here because otherwise we
        // cannot declare the variable 'side' below.
        cout << "Please enter the side length: ";
        double side;
        cin >> side;

        // We do not accept negative side lengths.
        if (side < 0) 
            cout << "There can be no squares with "
                 << "negative side lengths. Bye.\n";
        else
            cout << "The area is " << side * side 
                 << ".\n";
        break;
    }

    case 2: {
        // This is all the same as above, just for
        // circles.
        cout << "Please enter the radius: ";
        double radius;
        cin >> radius;
        if (radius < 0)
            cout << "There are no circles with "
                 << "negative radiuses. See you.\n";
        else
            cout << "The area is " 
                 << radius * radius * 3.1415926 
                 << ".\n";
        break;
    }

    default:
        // The user entered an invalid selection;
        // display an error message.
        cout << "Your selection isn't valid.\n";
        break;
    }
}

Exercises

Yes, exercises. You should do them. Really. You will not learn a programming language (or anything which has to do with computers) just reading. You must try it out, make mistakes, fiddle with it.

  1. Write a program asking for an integer number and saying whether it is positive or not. (Zero is not positive).

  2. Modify the previous program so that it says whether the number is positive, negative or zero.

  3. Write a program displaying a menu like some of the presented programs to let the user select one among some (at least 4) recipes, and display the recipe the user has chosen.

  4. Extend the previous program to detect if the user has made an invalid selection, and display an error message if he has done so.


next up previous contents
Next: Loops Up: Getting Started in C++ Previous: Doing Things With Objects   Contents
Aaron Isotton <aaron@isotton.com>
2003-02-24