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.
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.
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...
}
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.
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:
== 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.
!= is the opposite of ==. a != b is true if
a is not equal to b, false otherwise.
>, <, >=, <= are the greater, less,
greater or equal to and less or equal to operators,
respectively. They work just as you'd expect.
&& 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
&.
|| 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
|.
! is the logical not operator. It negates what
follows. For example, !(a > 10) is the same thing as
a <= 10.
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.
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.
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.
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.
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;
}
}
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.