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