Expressions¶
Arithmetic Operators¶
+, -, *, / have their usual means in arithmetic expressions
1 + 2 is 3
3 - 4 is -1
5 * 6 is 30
7 / 8 is 0
Arithmetic Operators¶
% is the mod operator (sometimes called the remainder operator)
6 % 2 is 0
3 % 4 is 3
5 % 5 is 0
15 % 10 is 5
a % b returns the remainder when a is divided by b
Two Kinds of Minus¶
unary minus: -6, -3.3, -1
binary minus: 8 - 6, 12 - 2, 1 - 1
there’s also unary plus: +6, +3.3, +1
Operator Precedence¶
unary +, unary - (highest precedence)
*, /, %
binary +, binary - (lowest precedence)
Operator Precedence¶
-3 + 22 / 11 * 2 - 3 % 2 * 2
same as -3 + 2 * 2 - 3 % 2 * 2
same as -3 + 2 * 2 - 1 * 2
same as -3 + 4 - 1 * 2
same as -3 + 4 - 2
same as -1
Round Brackets¶
( ) change the order of evaluation
1 + 2 * 3 is 7
(1 + 2) * 3 is 9
use them when you are unsure of operator precedence
Logical and Relational Operators¶
false || !true && 6 < 7
same as false || false && 6 < 7
same as false || false && true
same as false || false
same as false
Logical and Relational Operators¶
false || !true && 6 < 7
doesn’t compile using our strict warnings-are-errors makefile!
there’s a g++ warning that recommends re-writing the expression like this
false || (!true && 6 < 7)
Short-circuit Evaluation¶
expr1 && expr2
when this expression is evaluated, first expr1 is evaluated
expr2 is only evaluated if necessary, i.e. if expr1 is false, then
expr2 is not evaluated
false && expr2 is assumed to be false no matter the value of expr2
Short-circuit Evaluation¶
expr1 || expr2
when this expression is evaluated, first expr1 is evaluated
expr2 is only evaluated if necessary, i.e. if expr1 is true, then
expr2 is not evaluated
true || expr2 is assumed to be true no matter the value of expr2
Don’t Chain < and Friends¶
3 < 2 < 1 (false in mathematics)
same as false < 1
same as 0 < 1
same as true
Don’t Chain < and Friends¶
don’t write a < b < c (or similar expressions)
instead write a < b && a < c
Avoid Trickiness¶
C/C++ allows for all kinds of clever ways of mixing operators and types (see the textbook for some examples)
but avoid cleverness
write clear, straightforward code that a programmer can understand with minimal effort
Assignment¶
x = 5;
= is called the assignment operator
don’t use it in tricky ways (the textbook shows some examples)
Compound Assignment Operators¶
x += 3 adds 3 to x
y -= 2 subtracts 2 from x
z *= 1.5 multiplies z by 1.5
(see textbook for more such operators)
Increment Operators¶
++x pre-increment, adds 1 to x and returns the value of x
after the increment
x++ post-increment, adds 1 to x and returns the value of x
before the increment
Decrement Operators¶
similar to the increment operators, but instead subtract 1
--x pre-decrement, subtracts 1 from x and returns the value of
x before the decrement
x-- post-decrement, subtracts 1 from x and returns the value of
x after the decrement
Avoid Operators in Expressions¶
avoid using ++ and -- in expressions
the order of evaluation may surprise you, e.g.
int x = 4;
cout << x // prints 5 (!)
<< ++x // prints 5
<< x // prints 5
<< endl;
Avoid Incremener/Decrement Operators in Expressions¶
int x = 4;
cout << x // prints 5 (!)
<< ++x // prints 5
<< x // prints 5
<< endl;
the cout is one big expression and the order of evaluation of the parts of
an expression are not guaranteed
Operator Evaluation Order is Not Guaranteed¶
f() + g()
no guarantee f() is called before g()!
if evaluation order matters, rewrite it, e.g.
double x = f();
double y = g();
cout << x + y;
Member Access Operators¶
string s = "cat";
cout << s.size(); // . operator accesses a member of an object
string* p = &s;
cout << p->s; // p -> s is shorthand for (*p).s
cout << *p.size(); // error: . has higher precedence than *
cout << (*p).size(); // ok
The Conditional Operator¶
string result = (x > 50) ? "pass" : "fail";
if x > 50 is true, evaluate to "pass", else evaluate to "fail"
Conversions¶
conversions are a mess in C++
lots of rules
some are explicit, some are implicit (happen automatically)
generally, try to avoid mixing different types
Casts¶
cast are explicit conversions
double x = (double) 4; // C-style syntax
double y = double(4); // C++ style syntax
double z = static_cast<double>(4); // C++ template-style syntax
the third style is the most explicit, but it is long and ugly and so we will often use the second style for clarity
const_cast can be used to “cast away const”, i.e. to make a const
object non-const (see textbook)
we won’t discuss reinterpret_cast (see textbook)
Casting Advice¶
generally, avoid casts whenever possible
narrowing casts (e.g. 64 bit type to a 32 bit type) can chop off bits and so lose information
widening casts (e.g. 32 bit type to a 64 bit type) are usually safer
casting away const may be an indication of a design problem