Professional C__ - Marc Gregoire [6]
{
int someInteger = 256;
short someShort;
long someLong;
float someFloat;
double someDouble;
someInteger++;
someInteger *= 2;
someShort = (short)someInteger;
someLong = someShort * 10000;
someFloat = someLong + 0.785;
someDouble = (double)someFloat / 100000;
cout << someDouble << endl;
return 0;
}
Code snippet from typetest\typetest.cpp
The C++ compiler has a recipe for the order in which expressions are evaluated. If you have a complicated line of code with many operators, the order of execution may not be obvious. For that reason, it’s probably better to break up a complicated statement into several smaller statements or explicitly group expressions by using parentheses. For example, the following line of code is confusing unless you happen to know the C++ operator precedence table by heart:
int i = 34 + 8 * 2 + 21 / 7 % 2;
Adding parentheses makes it clear which operations are happening first:
int i = 34 + (8 * 2) + ( (21 / 7) % 2 );
Breaking up the statement into separate lines makes it even clearer:
int i = 8 * 2;
int j = 21 / 7;
j %= 2;
i = 34 + i + j;
For those of you playing along at home, all three approaches are equivalent and end up with i equal to 51. If you assumed that C++ evaluated expressions from left to right, your answer would have been 1. In fact, C++ evaluates /, *, and % first (in left-to-right order), followed by addition and subtraction, then bitwise operators. Parentheses let you explicitly tell the compiler that a certain operation should be evaluated separately.
Types
In C++, you can use the basic types (int, bool, etc.) to build more complex types of your own design. Once you are an experienced C++ programmer, you will rarely use the following techniques, which are features brought in from C, because classes are far more powerful. Still, it is important to know about the two most common ways of building types so that you will recognize the syntax.
Enumerated Types
An integer really represents a value within a sequence — the sequence of numbers. Enumerated types let you define your own sequences so that you can declare variables with values in that sequence. For example, in a chess program, you could represent each piece as an int, with constants for the piece types, as shown in the following code. The integers representing the types are marked const to indicate that they can never change.
const int kPieceTypeKing = 0;
const int kPieceTypeQueen = 1;
const int kPieceTypeRook = 2;
const int kPieceTypePawn = 3;
//etc.
int myPiece = kPieceTypeKing;
This representation is fine, but it can become dangerous. Since the piece is just an int, what would happen if another programmer added code to increment the value of the piece? By adding one, a king becomes a queen, which really makes no sense. Worse still, someone could come in and give a piece a value of -1, which has no corresponding constant.
Enumerated types solve these problems by tightly defining the range of values for a variable. The following code declares a new type, PieceT, which has four possible values, representing four of the chess pieces.
typedef enum { kPieceTypeKing, kPieceTypeQueen, kPieceTypeRook,
kPieceTypePawn } PieceT;
Behind the scenes, an enumerated type is just an integer value. The real value of kPieceTypeKing is zero. However, by defining the possible values for variables of type PieceT, your compiler can give you a warning or error if you attempt to perform arithmetic on PieceT variables or treat them as integers. The following code, which declares a PieceT variable, and then attempts to use it as an integer, results in a warning or error on most compilers.
PieceT myPiece;
myPiece = 0;
It’s also possible to specify the integer values for members of an enumeration. The syntax is as follows.
typedef enum { kPieceTypeKing = 1, kPieceTypeQueen, kPieceTypeRook = 10,
kPieceTypePawn } PieceT;
In this example, kPieceTypeKing has the integer value 1, kPieceTypeQueen has the value 2 assigned by the compiler, kPieceTypeRook has the value 10 and kPieceTypePawn has the value 11 assigned