Essentialssec2.htm

Essentials of C++: Section II


Operators

Declarations are statements. They state something to the compiler. Almost every bit of code we write in C++ is a statement. Here we focus on statements that use operators.

When you want to assign a value to some variable, you write an assignment statement. The simplest assignment statements use the assignment operator (=) to assign the value of one variable or constant to a variable:

variable1 = 3;
variable2 = variable 1;
More complex assignment statements can be formed through the use of additional operators. Such statements are called expressions. An expression uses some set of operators and lvalues that together form an instruction for a computer to perform. The two statements above are examples of simple expressions.

In what follows we discuss a subset of the C++ operators. All of these return a value although that value is often not important in the use of the operator.
 

A. Binary Arithmetic Operators and the Assignment Statement
Binary operators require two operands, that is, they require constants or lvalues on both sides of the operand. The most useful arithmetic binary operators built into C++ include:

+     Addition
- Subtraction
* Multiplication
/ Division
%
Modulus or Remainder

These can be combined in any number of ways and used with the assignment operator (=) to make complex arithmetic expressions such as:

value1 = value2 + value3 * value4 / value5;

There are also a number of operators that combine assignment with some other arithmetic operator:

+= Add rvalue to lvalue and store the result in the lvalue.
-= Subtract rvalue from lvalue and store the result in the lvalue.
*= Multiply lvalue by rvalue and store the result in the lvalue.
/= Divide lvalue by rvalue and store the result in the lvalue.
%=
Calculate modulus of lvalue divided by rvalue and store the result in the lvalue.
For example,
sum += value;

is another way of writing:

sum = sum + value;

B. Unary Arithmetic Operators
Some operators require only a single operand. The two most familiar are:

-
+

For example:

-5,     -value,     +3,     +sum

The other two most commonly used unary arithmetic operators are:

++    increment the lvalue by 1;
--     decrement the lvalue by 1;

These can be used both as prefix and postfix operators meaning that the '++' or '--' can be placed before or after the lvalue and the results of the computation will be different. When placed before an lvalue as in:

++value1;

the lvalue is modified first and then its value is returned. When placed after an lvalue as in:

value1--;

the value is returned before it is incremented.

 

C. Relational Operators
Often a program requires that a comparison be made between two values. For this the relational operators are used:

==     Equal to
>!= Not equal to
< Less than
> Greater than
<= Less than or equal to
>=
Greater than or equal to

These can be used to create expressions such as

value1 < value 2

which cause a computer to compare the value of the two variables and return true (some value other than 0) or false (the value 0). They can also be used with the assignment operator as in:

value3 = value1 < value 2;

This causes the system to compare 'value1' with 'value2' and store true or false in 'value3'. See the iteration and selection statements below for examples using these operators.

D. Logical Operators
Often associated with the relational operators are the logical operators for representing AND, OR, and NOT.

&&     representing AND
|| representing OR
! representing NOT

The first two are binary operators and require two expressions. The '&&' operator returns a non-zero value (true) if both expressions are true, otherwise it returns false. The '||' operator returns a non-zero value if one or both of the expressions is true. The last one is a unary operator that returns true if the expression associated with it is false and vs versa. Most often these operators are used with relational expressions as in:

(value1 > 0) && (value1 < 10)

Description in "The Story of C++"

E. Other Operators
There is a small set of C++ operators not discussed here because they are not seen as terribly important and are not used in this course. The other useful operators include:

( ) Used as a function call operator and in type casting
[] Used to designate a specific element of an array
* The Dereferencing operator - used with pointers
:: The scope resolution operator - used most commonly with classes
. For selecting an element of a structure or a public element of a class
-> For indirectly selecting (through a pointer) a member of a structure or a class
new To allocate dynamic memory
delete   
To deallocate dynamic memory

These operators are only vaguely described above and in some cases they have broader application than mentioned. Where provided, you should follow the links to the relevant sections for more information.

 

F. Operator Precedence
For complex expressions, the order in which operations are performed can make a difference in the result. The usual examples of this involve arithmetic expressions such as:

result = value1 * value2 - value3;

Most programming languages give a higher priority (precedence) to multiplication (*) and thus in this example the operation 'value1 * value2' will be performed before 'value3' is subtracted. If one wants the operation 'value2 - value3' performed first, one must use parentheses as in:

result = value1 * (value2 - value3);

A more complex example involves the logical operators. Assume that 'E1', 'E2', and 'E3' below are expressions that return true or false. The result of the following expression, then, depends not only on the truth values of 'E1', 'E2' and 'E3' but on the order in which the '&&' and '||' (AND and OR) operations are performed:

E1 && E2 || E3

The specifications for a programming language must indicate the order of precedence for all operators in the language to ensure that all implementations of the language produce the same results. In C++ the precedence for the operators listed above is as follows (from highest to lowest):

The Operator Precedence Table

::   ()    []    ->    .
!   ~    ++   --   *(the dereferencing operator)   + -(the unary versions of these)
new   delete
*     /    %
+     -
<<     >>
<     <=     >     >=
==     !=
&&
||
=     *=    /=    %=    +=    -=

This tells us that in the logical expression above, the operation 'E1 && E2' will be performed first. If one wants the '||' operation performed first, parentheses should be used as in:

E1 && (E2 || E3)

 

G. Type Conversions

Most operators assume that their operands are of the same type. Thus, it is not possible to add an integer and a string - what would be the meaning of such an operation? However, if this rule of 'sameness' were enforced too strictly, it would make C++ an awkward language. For example, it makes sense to add an integer to a long or to a double. To handle this C++ allows what are called implicit conversions (also called type coercions) of one operand to the type of a second operand - when the conversion is appropriate. In the example involving the addition of an int and a long, the integer would be converted to a long. In the example involving an int and a double, the integer would be converted to a double. Such conversions are called 'implicit' conversions because they take place automatically.

C++ provides a set of conversion rules (also called 'promotion' rules) that guide the type of implicit conversions that take place. These rules are based on the principle of "no surprises". This refers to the idea that a programming language should be designed to provide warnings or somehow make it more difficult for programmers to write code that results in 'strange' answers. In other words, implicit type conversions should only be allowed when the results are not likely to produce unexpected results. As an example of an 'unexpected' result: one could, in principle, allow values of type double to be implicitly converted to integers. The most likely way to do this would be to drop the information to the right of the decimal point. However, if this is allowed and a programmer forgets what this means, he or she is likely to be surprised with the calculations produced by a program using such conversions.

The built-in types of C++ are arranged in order from 'lower' to 'higher' types, where a value of a lower type can be implicitly converted to a value of a higher type. 'Higher' here essentially means that the type can hold all the information contained in a 'lower' type and no information is lost in a conversion. Thus, C++ will implicitly convert an int to a double but not a double to an int. In the latter case, information is lost when the 'data' to the right of the decimal point is truncated.

Here is that part of the conversion hierarchy listing the types described above in Section I:

double
float
long
int
char     (by default, enums are represent in one byte, the same as chars)

The precise rules for implicit conversions can be found in C++ manuals.

C++ does allow programmers to make their own explicit conversions. This allows the programmer who is willing to accept the risk, to do whatever he or she wishes. First, one can explicitly assign a value of a higher type to a variable of a lower type as in:

int z = 3.12;

or

double x = 2.12
double y = 3.12
int z;
z = x + y;

In both these cases the answer will be truncated when it is stored in the variable 'x'.

Similarly, one can use a value of a higher type as the actual argument in a call to a function with a corresponding formal argument of a lower type. This is seen as a type of assignment.

Finally, one can type cast values from one type to another. To do this, one writes the name of the type to be converted to, followed by a set of parentheses surrounding the variable or expression to be converted. For example,

double w;
int x;
int y;
y = int (w) + x;.

explicitly converts the variable 'w' into an integer before adding it to 'x'.

Links to 'The Story of C++" and other documents

The Assignment Operator
Artithmetic Operators and Precedence
Relational Operators
Logical Operators and Precedence
++ and --

Top of Section Main Menu of Essentials of C++ Next Section