C++: Logical Operators

'If' statements provide an excellent way to do certain things under certain conditions, however sometimes more complex conditions are required to accomplish the desired goal. Logical operators, sometimes called boolean operators, evaluate expressions and decide what boolean should be expressed from the evaluation. The name "boolean operators" is appropriate as the operators take boolean expression(s) - combinations of symbols which represent boolean (true or false) values - and evaluate these into a single boolean expression. If you don't quite understand what I'm talking about here, don't worry about it, it's probably because I'm having to jump around the point a little bit while generalizing about these operators - let's jump right in.

And

The "and" operator in C++ is represented by two ampersand signs next to each other: &&. It takes the boolean value on the left of the operator and the boolean value on the right of the operator, and returns true if both are true, and false in all other conditions. From this, you can see that it behaves much like the word "and" does in the English language - if condition A and condition B are true, then the expression will be true, otherwise the expression will be false. This means that true && true will evaluate to true, and true && false will evaluate to false -- both conditions must be true for the expression to be true.

Following on from the concept demonstrated above, the regular ol' conditions that we've been using in if-statements end up evaluating to boolean values - being true if the condition is true, and false if it is not. This means that we can put a condition at each side of the && operator, and the full expression will only return true if the first condition and the second condition are true. An example of this is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
	int age;
	cout << "Enter your age: ";
	cin >> age;

	if(age >= 35 && age <= 80)
	{
		cout << "You're between 35 and 80 and can save money on your car insurance!" << endl;
	}
	else
	{
		cout << "Sorry, we don't have any deals for you today!" << endl;
	}

	return 0;
}

Or

The "or" operator behaves much like "and", however only one of the two conditions has to be true. It is represented by a double "pipe symbol", ||, and behaves much like the word "or" in the English language - if one condition or the other is true. This means that true || true, true || false, and false || true will all return true, and false || false will return false. This functionality, once again, is best seen in a code snippet in which a complex condition can be given to an 'if' statement:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
	int age;
	cout << "Enter your age: ";
	cin >> age;

	if(age < 0 || age > 160)
	{
		cout << "You're lying - you CANNOT be that age." << endl;
	}
	else
	{
		cout << "Thanks for inputting your age!" << endl;
	}

	return 0;
}

Not

The "not" operator is a little different to "and" and "or". It can only be prefixed to single expressions and essentially just inverts the boolean value of an expression. If the value is true, "not" will flick it to false - the "not" operator is expressed via an exclamation mark, and hence !true is false, and !false is true. The functionality of the "not" operator can almost always be accomplished via different means, for example !(age > 5) could be expressed as age < 5, however "not" really shines with readability, more complex expressions, and boolean variables. Take, for example, the following, which uses the "not" operator to create a neater condition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
	bool want_to_start;

	cout << "Do you want to start the application? [0: No] [1: Yes]" << endl;
	cin >> want_to_start; //An input of 0 is 'false', and 1 is 'true'

	if(!want_to_start)
	{
		cout << "Then why open the application? Idiot, too bad, I'm starting anyway." << endl;
	}

	cout << "Application starting." << endl;
	//Continue main program code here

	return 0;
}

Another really cool use for "not" is making use of some of the error handling built into a lot of the standard stuff in a really nice way. A really cool example of this is error handling input via "cin". If you've used 'cin' for getting data into an integer variable before, for example, you may have noticed that things go horribly wrong if the user types in text data. "cin" actually sort of handles this kind of thing for us, we just haven't been utilizing it yet! If the user enters text data when "cin" is getting data for an integer value, for example, it will actually return false - which means we can pick up on this and act appropriately (do some error handling!). This means that a simple check can be done to see if the user input was valid with something like the following:

1
2
3
4
5
6
7
int age;

cout << "Enter an integer, age: ";
if(!(cin >> age)) //If 'cin >>' isn't happy (it returned false)
{
	cout << "What the frick are you doing?! I said enter an integer, idiot!" << endl;
}

It's worth nothing that in this example, we should probably be using cerr instead of cout. They're very similar, and I won't go into the technical details (Google if you're interested), but simply put, you should use cerr for outputting errors (used exactly the same as cout), and cout for just outputting text normally.