Member since Mar 17, 2009, follows 0 people, 0 public groups, 1144 public bookmarks (1162 total).
More »
Tags
| Recent Tags: | |
|---|---|
| Top Tags: |
More »
Recent Bookmarks and Annotations
-
Teach Yourself C++ in 21 Days 27 minutes ago
-
An array is a collection of data storage locations, each of which holds the same
type of data -
An array is a collection of data storage locations, each of which holds the same
type of data. Each storage location is called an element of the array. - 14 more annotations...
-
-
long LongArray[25];
declares an array of 25 long integers, named LongArray.
When the compiler sees this declaration, it sets aside enough memory to hold all
25 elements -
Array elements are counted from zero. Therefore, the first array element is
arrayName[0]. -
Suppose that you ask to write over the value at LongArray[5], which is
the sixth element. The compiler multiplies the offset (5) by the size of each
element--in this case, 4. It then moves that many bytes (20) from the beginning
of the array and writes the new value at that location. -
If you ask to write at LongArray[50], the compiler ignores the fact
that there is no such element. It computes how far past the first element it
should look (200 bytes) and then writes over whatever is at that location. This
can be virtually any data, and writing your new value there might have
unpredictable results -
The compiler is like a blind man pacing off the distance from a house.
-
It is so common to write to one past the end of an array that this bug has its
own name. It is called a fence post error -
If you omit the size of the array, an array just big enough to hold the
initialization is created. -
int IntegerArray[] = { 10, 20, 30, 40, 50 }; -
If you need to know the size of the array, you can ask the compiler to
compute it for you. For example,const USHORT IntegerArrayLength;
IntegerArrayLength = sizeof(IntegerArray)/sizeof(IntegerArray[0]); -
It is legal, however,
to writeint IntegerArray[5] = { 10, 20};Although uninitialized array members have no guaranteed values, actually,
aggregates will be initialized to 0. If you don't initialize an array
member, its value will be set to 0. -
Arrays can have any legal variable name, but they cannot have the same name as
another variable or array within their scope. -
Any object, whether built-in or user-defined, can be stored in an array. When
you declare the array, you tell the compiler the type of object to store and the
number of objects for which to allocate room. The compiler knows how much room
is needed for each object based on the class declaration. The class must have a
default constructor that takes no arguments so that the objects can be created
when the array is defined. -
Accessing member data in an array of objects is a two-step process. You identify
the member of the array by using the index operator ([ ]), and then you
add the member operator (.) to access the particular member variable -
21: CAT Litter[5];
22: int i;
23: for (i = 0; i < 5; i++)
24: Litter[i].SetAge(2*i +1);
-
-
-
Teach Yourself C++ in 21 Days about 1 hour ago
-
1: Rectangle::Rectangle():
2: itsWidth(5),
3: itsLength(10)
4: {
5: };
6:
7: Rectangle::Rectangle (int width, int length)
8: itsWidth(width),
9: itsLength(length)
10:
11: }; -
5: enum BOOL { FALSE, TRUE};
- 28 more annotations...
-
-
5: enum BOOL { FALSE, TRUE};
-
5: enum BOOL { FALSE, TRUE};
-
5: enum BOOL { FALSE, TRUE};
-
function overloading, by writing two or more functions with the same name but
with different parameters. Class member functions can be overloaded as well, in
much the same way. -
5: enum BOOL { FALSE, TRUE};
-
8: class Rectangle
9: {
10: public:
11: // constructors
12: Rectangle(USHORT width, USHORT height);
13: ~Rectangle(){}
14:
15: // overloaded class function DrawShape
16: void DrawShape() const;
17: void DrawShape(USHORT aWidth, USHORT aHeight) const; -
32: // Overloaded DrawShape - takes no values
33: // Draws based on current class member values
34: void Rectangle::DrawShape() const
35: {
36: DrawShape( itsWidth, itsHeight);
37: }
38:
39:
40: // overloaded DrawShape - takes two values
41: // draws shape based on the parameters
42: void Rectangle::DrawShape(USHORT width, USHORT height) const
43: {
44: for (USHORT i = 0; i<height; i++)
45: {
46: for (USHORT j = 0; j< width; j++)
47: {
48: cout << "*";
49: }
50: cout << "\n";
51: }
52: } -
55: int main()
56: {
57: // initialize a rectangle to 30,5
58: Rectangle theRect(30,5);
59: cout << "DrawShape(): \n";
60: theRect.DrawShape();
61: cout << "\nDrawShape(40,2): \n";
62: theRect.DrawShape(40,2); -
Output: DrawShape():
******************************
******************************
******************************
******************************
******************************
DrawShape(40,2):
************************************************************
************************************************************ -
The compiler decides which method to call based on the number and type of
parameters entered. -
Just as non-class functions can have one or more default values, so can each
member function of a class. The same rules apply for declaring the default
values -
10: public:
11: // constructors
12: Rectangle(USHORT width, USHORT height);
13: ~Rectangle(){}
14: void DrawShape(USHORT aWidth, USHORT aHeight, BOOL UseCurrentVals = Â FALSE) const; -
--it is easy to extend the overloaded functions. The default value, however,
will quickly become unusably complex as new variations are added. -
The constructor provided for you is called the "default" constructor, but by
convention so is any constructor that takes no parameters. This can be a bit
confusing, but it is usually clear from context which is meant.Take note that if you make any constructors at all, the default constructor
is not made by the compiler. So if you want a constructor that takes no
parameters and you've created any other constructors, you must make the default
constructor yourself! -
The point of a constructor is to establish the object; for example, the point
Before the constructor
of a Rectangle constructor is to make a rectangle.
runs, there is no rectangle, just an area of memory. After the constructor
finishes, there is a complete, ready-to-use rectangle object.Constructors, like all member functions, can be overloaded. The ability to
overload constructors is very powerful and very flexible. -
6: class Rectangle
7: {
8: public:
9: Rectangle();
10: Rectangle(int width, int length); -
8: public:
9: Rectangle();
10: Rectangle(int width, int length); -
19: Rectangle::Rectangle()
20: {
21: itsWidth = 5;
22: itsLength = 10;
23: }
24:
25: Rectangle::Rectangle (int width, int length)
26: {
27: itsWidth = width;
28: itsLength = length;
29: } -
Up to now, you've been setting the member variables of objects in the body of
the constructor. Constructors, however, are invoked in two stages: the
initialization stage and the body.
Most variables can be set in either
stage, either by initializing in the initialization stage or by assigning in the
body of the constructor. It is cleaner, and often more efficient, to initialize
member variables at the initialization stage -
Up to now, you've been setting the member variables of objects in the body of
the constructor. Constructors, however, are invoked in two stages: the
initialization stage and the body. -
It is cleaner, and often more efficient, to initialize member variables at the
initialization stage. -
1: Rectangle::Rectangle():
2: itsWidth(5),
3: itsLength(10)
4: {
5: };
6:
7: Rectangle::Rectangle (int width, int length)
8: itsWidth(width),
9: itsLength(length)
10:
11: }; -
In addition to providing a default constructor and destructor, the compiler
provides a default copy constructor. The copy constructor is called every time a
copy of an object is made.When you pass an object by value, either into a function or as a function's
return value, a temporary copy of that object is made. -
All copy constructors take one parameter, a reference to an object of the
same class. It is a good idea to make it a constant reference, because the
constructor will not have to alter the object passed in. For example:CAT(const CAT & theCat);
Here the CAT constructor takes a constant reference to an existing
CAT object. The goal of the copy constructor is to make a copy of
theCAT. -
The default copy constructor simply copies each member variable from the
object passed as a parameter to the member variables of the new object. This is
called a member-wise (or shallow) copy, and although this is fine for most
member variables, it breaks pretty quickly for member variables that are
pointers to objects on the free store. -
This will lead to a disaster when either CAT goes out of scope. As
mentioned on Day 8, "Pointers," the job of the destructor is to clean up this
memory. If the original CAT's destructor frees this memory and the new
CAT is still pointing to the memory, a stray pointer has been created,
and the program is in mortal danger -
The solution to this is to create your own copy constructor and to allocate the
memory as required. Once the memory is allocated, the old values can be copied
into the new memory. This is called a deep copy
-
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
A reference is an alias; when you create a reference, you initialize it with the
name of another object, the target. From that moment on, the reference acts as an
alternative name for the target, and anything you do to the reference is really done
to the target. - 47 more annotations...
-
-
int &rSomeRef = someInt;
This is read as "rSomeRef is a reference to an integer that is initialized
to refer to someInt." -
8: int intOne;
9: int &rSomeRef = intOne;
10:
11: intOne = 5;
12: cout << "intOne: " << intOne << endl;
13: cout << "rSomeRef: " << rSomeRef << endl;
14:
15: rSomeRef = 7;
16: cout << "intOne: " << intOne << endl;
17: cout << "rSomeRef: " << rSomeRef << endl; -
Output: intOne: 5
rSomeRef: 5
intOne: 7
rSomeRef: 7 -
15: cout << "&intOne: " << &intOne << endl;
16: cout << "&rSomeRef: " << &rSomeRef << endl; -
&intOne: 0x3500
&rSomeRef: 0x3500 -
C++ gives you
no way to access the address of the reference itself because it is not meaningful,
as it would be if you were using a pointer or other variable. -
President William_Jefferson_Clinton;
You might then declare a reference to President and initialize it with
this object:President &Bill_Clinton = William_Jefferson_Clinton;
There is only one President; both identifiers refer to the same object
of the same class. Any action you take on Bill_Clinton will be taken on
William_Jefferson_Clinton as well. -
references cannot be
reassigned and are always aliases for their target -
What appears to be a reassignment turns out
to be the assignment of a new value to the target. -
17: int intTwo = 8;
18: rSomeRef = intTwo; // not what you think!
19: cout << "\nintOne:\t" << intOne << endl;
20: cout << "intTwo:\t" << intTwo << endl;
21: cout << "rSomeRef:\t" << rSomeRef << endl; -
17: int intTwo = 8;
18: rSomeRef = intTwo; // not what you think! -
intOne: 8
intTwo: 8
rSomeRef: 8 -
Any object can be referenced, including user-defined objects.
-
Member data and methods
are accessed using the normal class member access operator (.) -
26: SimpleCat Frisky(5,8);
27: SimpleCat & rCat = Frisky;
28:
29: cout << "Frisky is: ";
30: cout << Frisky.GetAge() << " years old. \n";
31: cout << "And Frisky weighs: ";
32: cout << rCat.GetWeight() << " pounds. \n"; -
a reference cannot be null, and a program with a reference to a null object is considered
an invalid program. When a program is invalid, just about anything can happen. -
In C++, passing by reference is accomplished in two ways: using pointers and using
references. The syntax is different, but the net effect is the same. Rather than
a copy being created within the scope of the function, the actual original object
is passed into the function. -
When you pass in a pointer, you pass in the address of the object, and thus the
function can manipulate the value at that address. -
5: void swap(int *x, int *y);
6:
7: int main()
8: {
9: int x = 5, y = 10;
10:
11: cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
12: swap(&x,&y);
13: cout << "Main. After swap, x: " << x << " y: " << y << "\n";
14: return 0;
15: }
16
17: void swap (int *px, int *py)
18: {
19: int temp;
20:
21: cout << "Swap. Before swap, *px: " << *px << " *py: " << *py << "\n";
22:
23: temp = *px;
24: *px = *py;
25: *py = temp;
26:
27: cout << "Swap. After swap, *px: " << *px << " *py: " << *py << "\n";
28:
29: } -
The preceding program works, but the syntax of the swap() function is
cumbersome in two ways. First, the repeated need to dereference the pointers within
the swap() function makes it error-prone and hard to read. Second, the need
to pass the address of the variables in the calling function makes the inner workings
of swap() overly apparent to its users. -
6: void swap(int &x, int &y);
7:
8: int main()
9: {
10: int x = 5, y = 10;
11:
12: cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
13: swap(x,y);
14: cout << "Main. After swap, x: " << x << " y: " << y << "\n";
15: return 0;
16: }
17:
18: void swap (int &rx, int &ry)
19: {
20: int temp;
21:
22: cout << "Swap. Before swap, rx: " << rx << " ry: " << ry << "\n";
23:
24: temp = rx;
25: rx = ry;
26: ry = temp;
27:
28: cout << "Swap. After swap, rx: " << rx << " ry: " << ry << "\n";
29:
30: } -
On line 13, the function swap() is called, but note that x
and y, not their addresses, are passed. -
program execution jumps to line 18, where the variables
are identified as references. -
Their values are printed on line 22, but note that
no special operators are required. These are aliases for the original values, and
can be used as such. -
References provide the convenience and ease of use of normal variables, with the
power and pass-by-reference capability of pointers! -
As discussed, functions can only return one value. What if you need to get two
values back from a function? One way to solve this problem is to pass two objects
into the function, by reference. The function can then fill the objects with the
correct values. Since passing by reference allows a function to change the original
objects, this effectively lets the function return two pieces of information. This
approach bypasses the return value of the function, which can then be reserved for
reporting errors.Once again, this can be done with references or pointers.
-
easier to read and maintain by using
references rather than pointers. -
7: typedef unsigned short USHORT;
8: enum ERR_CODE { SUCCESS, ERROR };
9:
10: ERR_CODE Factor(USHORT, USHORT&, USHORT&);
11:
12: int main()
13: {
14: USHORT number, squared, cubed;
15: ERR_CODE result;
16:
17: cout << "Enter a number (0 - 20): ";
18: cin >> number;
19:
20: result = Factor(number, squared, cubed);
21:
22: if (result == SUCCESS)
23: {
24: cout << "number: " << number << "\n";
25: cout << "square: " << squared << "\n";
26: cout << "cubed: " << cubed << "\n";
27: }
28: else
29: cout << "Error encountered!!\n";
30: return 0;
31: }
32:
33: ERR_CODE Factor(USHORT n, USHORT &rSquared, USHORT &rCubed)
34: {
35: if (n > 20)
36: return ERROR; // simple error code
37: else
38: {
39: rSquared = n*n;
40: rCubed = n*n*n;
41: return SUCCESS;
42: }
43: }
Output: Enter a number (0 - 20): 3
number: 3
square: 9
cubed: 27 -
Each time you pass an object into a function by value, a copy of the object is
made. Each time you return an object from a function by value, another copy is made. -
With the classes you create, each of these temporary
copies is created when the compiler calls a special constructor: the copy constructor. -
When the temporary object is destroyed, which happens when the function returns,
the object's destructor is called. If an object is returned by the function by value,
a copy of that object must be made and destroyed as well.With large objects, these constructor and destructor calls can be expensive in
speed and use of memory. -
Although passing a pointer to FunctionTwo() is more efficient, it is
dangerous. FunctionTwo() is not allowed to change the SimpleCat
object it is passed, yet it is given the address of the SimpleCat. This
seriously exposes the object to change and defeats the protection offered in passing
by value. -
The solution is to pass a const pointer to SimpleCat. Doing
so prevents calling any non-const method on SimpleCat, and thus
protects the object from change. -
Since you know the object will never be null, it would be easier to work with
in the function if a reference were passed in, rather than a pointer. -
52: // functionTwo, passes a ref to a const object
53: const SimpleCat & FunctionTwo (const SimpleCat & theCat)
54: {
55: cout << "Function Two. Returning...\n";
56: cout << "Frisky is now " << theCat.GetAge();
57: cout << " years old \n";
58: // theCat.SetAge(8); const!
59: return theCat;
60: } -
FunctionTwo() now takes and returns a reference to a constant object. Once
again, working with references is somewhat simpler than working with pointers, and
the same savings and efficiency are achieved, as well as the safety provided by using
const. -
C++ programmers do not usually differentiate between "constant reference
to a SimpleCat object" and "reference to a constant SimpleCat
object." References themselves can never be reassigned to refer to another object,
and so are always constant. If the keyword const is applied to a reference,
it is to make the object referred to constant. -
C++ programmers strongly prefer references to pointers. References are cleaner
and easier to use, and they do a better job of hiding information -
References cannot be reassigned, however. If you need to point first to one object
and then another, you must use a pointer. -
References cannot be null, so if there
is any chance that the object in question may be null, you must not use a reference.
You must use a pointer. -
An example of the latter concern is the operator new. If new
cannot allocate memory on the free store, it returns a null pointer. Since a reference
can't be null, you must not initialize a reference to this memory until you've checked
that it is not null. The following example shows how to handle this:int *pInt = new int;
if (pInt != NULL)
int &rInt = *pInt;In this example a pointer to int, pInt, is declared and initialized with
the memory returned by the operator new. The address in pInt is
tested, and if it is not null, pInt is dereferenced. The result of dereferencing
an int variable is an int object, and rInt is initialized
to refer to that object. Thus, rInt becomes an alias to the int
returned by the operator new. -
The question of where to put the
reference (&) or indirection (*) operator when declaring these
variables is a great controversy. You may legally write any of the following: -
1: CAT& rFrisky;
2: CAT & rFrisky;
3: CAT &rFrisky;White space is completely ignored, so anywhere you see a space here you may put
as many spaces, tabs, and new lines as you like. -
having the &
near the CAT can lead to the following bug:CAT& rFrisky, rBoots;
Casual examination of this line would lead you to think that both rFrisky
and rBoots are references to CAT objects, but you'd be wrong. This
really says that rFrisky is a reference to a CAT, and rBoots
(despite its name) is not a reference but a plain old CAT variable. -
many programmers opt out of the argument and go with the middle position
-
When your program allocates memory on the free store, a pointer is returned. It
is imperative that you keep a pointer to that memory, because once the pointer is
lost, the memory cannot be deleted and becomes a memory leak.As you pass this block of memory between functions, someone will "own"
the pointer. Typically the value in the block will be passed using references, and
the function that created the memory is the one that deletes it. But this is a general
rule, not an ironclad one. -
It is safer to build your functions so that they delete the memory
they create.
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
- Write your prototype into a file, and then use the #include
directive to include it in your program. - Write the prototype into the file in which your function is used.
- Define the function before it is called by any other function. When you do
this, the definition acts as its own declaration.
There are three ways to declare a function:
- Write your prototype into a file, and then use the #include
- 37 more annotations...
-
-
function prototypes are a good and powerful debugging technique. If your
prototype declares that your function takes a particular set of parameters, or
that it returns a particular type of value, and then your function does not
match the prototype, the compiler can flag your error instead of waiting for it
to show itself when you run the program. -
The function prototype is a statement, which means it ends with a semicolon.
It consists of the function's return type, name, and parameter list. -
long Area(int length, int width);
-
all functions have a
return type. If none is explicitly stated, the return type defaults to
int -
3: typedef unsigned short USHORT;
4: #include <iostream.h>
5: USHORT FindArea(USHORT length, USHORT width); //function prototype
6:
7: int main()
8: {
9: USHORT lengthOfYard;
10: USHORT widthOfYard;
11: USHORT areaOfYard; -
18: areaOfYard= FindArea(lengthOfYard,widthOfYard);
-
26: USHORT FindArea(USHORT l, USHORT w)
27: {
28: return l * w;
29: } -
you also can declare variables within the body of the function. This is done
using local variables, so named because they exist only locally within the
function itself. When the function returns, the local variables are no longer
available. -
Variables defined outside of any function have global scope and thus are
available from any function in the program, including main().Local variables with the same name as global variables do not change the
global variables. A local variable with the same name as a global variable hides
the global variable, however. If a function has a variable with the same name as
a global variable, the name refers to the local variable--not the global--when
used within the function. -
4: int x = 5, y = 7; // global variables
5: int main()
6: { -
In C++, global variables are legal, but they are almost never used
-
Globals are dangerous because they are shared data, and one function can change
a global variable in a way that is invisible to another function. -
The scope of the variable is the block in which it is defined. Thus, if you
define a variable inside a set of braces within the function, that variable is
available only within that block. -
19: void myFunc()
20: {
21:
22: int x = 8;
23: cout << "\nIn myFunc, local x: " << x << endl;
24:
25: {
26: cout << "\nIn block in myFunc, x is: " << x;
27:
28: int x = 9;
29:
30: cout << "\nVery local x: " << x;
31: }
32:
33: cout << "\nOut of block, in myFunc, x: " << x << endl;
34: }
Output: In main x is: 5
In myFunc, local x: 8
In block in myFunc, x is: 8
Very local x: 9
Out of block, in myFunc, x: 8
Back in main, x is: 5 -
The arguments passed in to the function are local to the function. Changes made
to the arguments do not affect the values in the calling function. This is known
as passing by value, which means a local copy of each argument is made in the
function. -
It is legal to have more than one return statement in a single function
-
A default value is a value to use if none is supplied
-
C++ enables you to create more than one function with the same name. This is
called function overloading. The functions must differ in their parameter list,
with a different type of parameter, a different number of parameters, or both.
Here's an example:int myFunction (int, int);
int myFunction (long, long);
int myFunction (long); -
Function overloading i s also called function polymorphism
-
Suppose you write a function that doubles whatever input you give it. You
would like to be able to pass in an int, a long, a
float, or a double. Without function overloading, you would
have to create four function names:int DoubleInt(int);
long DoubleLong(long);
float DoubleFloat(float);
double DoubleDouble(double);With function overloading, you make this declaration:
int Double(int);
long Double(long);
float Double(float);
double Double(double);This is easier to read and easier to use. You don't have to worry about which
one to call; you just pass in a variable, and the right function is called
automatically. -
The compiler examines the arguments and chooses which of the four
Double() functions to call -
When you define a function, normally the compiler creates just one set of
instructions in memory. When you call the function, execution of the program
jumps to those instructions, and when the function returns, execution jumps back
to the next line in the calling function -
some functions are very small, just a line or two of code, and some efficiency
can be gained if the program can avoid making these jumps just to execute one or
two instructions. -
If a function is declared with the keyword inline, the compiler does
not create a real function: it copies the code from the inline function directly
into the calling function. No jump is made; it is just as if you had written the
statements of the function right into the calling function. -
Note that inline functions can bring a heavy cost. If the function is called
10 times, the inline code is copied into the calling functions each of those 10
times. The tiny improvement in speed you might achieve is more than swamped by
the increase in size of the executable program. Even the speed increase might be
illusory. First, today's optimizing compilers do a terrific job on their own,
and there is almost never a big gain from declaring a function inline.
More important, the increased size brings its own performance cost.What's the rule of thumb? If you have a small function, one or two
statements, it is a candidate for inline. When in doubt, though, leave
it out -
Inline is a hint to the compiler that you would like the function to be inlined.
The compiler is free to ignore the hint and make a real function call. -
A function can call itself. This is called recursion, and recursion can be
direct or indirect. It is direct when a function calls itself; it is indirect
recursion when a function calls another function that then calls the first
function. -
Registers are a special area of memory built right into the Central Processing
Unit (or CPU). They take care of internal housekeeping. -
the set of registers responsible for pointing, at any given moment, to the next line
of code. We'll call these registers, together, the instruction pointer. -
code space, which is that part of memory set aside to hold
the binary form of the instructions you created in your program. Each line of source
code is translated into a series of instructions, and each of these instructions
is at a particular address in memory. The instruction pointer has the address of
the next instruction to execute. -
The stack is a special area of memory allocated for your program to hold the data
required by each of the functions in your program. It is called a stack because it
is a last-in, first-out queue -
When data is "pushed" onto the stack, the stack grows; as data is "popped"
off the stack, the stack shrinks. It isn't possible to pop a dish off the stack without
first popping off all the dishes placed on after that dish. -
A more accurate mental picture is of a series of cubbyholes
aligned top to bottom. The top of the stack is whatever cubby the stack pointer (which
is another register) happens to be pointing to.Each of the cubbies has a sequential address, and one of those addresses is kept
in the stack pointer register. Everything below that magic address, known as the
top of the stack, is considered to be on the stack. Everything above the top of the
stack is considered to be off the stack and invalid. -
When data is put on the stack, it is placed into a cubby above the stack pointer,
and then the stack pointer is moved to the new data. When data is popped off the
stack, all that really happens is that the address of the stack pointer is changed
by moving it down the stack. -
Here's what happens when a program, running on a PC under DOS, branches to a function:
- 1. The address in the instruction pointer is incremented to the next instruction
past the function call. That address is then placed on the stack, and it will be
the return address when the function returns.
2. Room is made on the stack for the return type you've declared. On a system
with two-byte integers, if the return type is declared to be int, another
two bytes are added to the stack, but no value is placed in these bytes.
3. The address of the called function, which is kept in a special area of
memory set aside for that purpose, is loaded into the instruction pointer, so the
next instruction executed will be in the called function.
4. The current top of the stack is now noted and is held in a special pointer
called the stack frame. Everything added to the stack from now until the function
returns will be considered
"local" to the function.
5. All the arguments to the function are placed on the stack.
6. The instruction now in the instruction pointer is executed, thus executing
the first instruction in the function.
7. Local variables are pushed onto the stack as they are defined.
When the function is ready to return, the return value is placed in the area of
the stack reserved at step 2. The stack is then popped all the way up to the stack
frame pointer, which effectively throws away all the local variables and the arguments
to the function.The return value is popped off the stack and assigned as the value of the function
call itself, and the address stashed away in step 1 is retrieved and put into the
instruction pointer. The program thus resumes immediately after the function call,
with the value of the function retrieved. - 1. The address in the instruction pointer is incremented to the next instruction
-
Some of the details of this process change from compiler to compiler, or between
computers, but the essential ideas are consistent across environments. In general,
when you call a function, the return address and the parameters are put on the stack.
During the life of the function, local variables are added to the stack. When the
function returns, these are all removed by popping the stack. -
When you begin your program, your operating system (such as DOS or Microsoft
Windows) sets up various areas of memory based on the requirements of your
compiler. As a C++ programmer, you'll often be concerned with the global name
space, the free store, the registers, the code space, and the stack.
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
A pointer is a variable that holds a memory address.
- 42 more annotations...
-
-
Usually programmers don't need to know the particular address of any given
variable, because the compiler handles the details. If you want this
information, though, you can use the address of operator
(&), -
Even without knowing the specific address of a given variable, you can store
that address in a pointer. -
int *pAge = 0;
This declares pAge to be a pointer to int. That is,
pAge is declared to hold the address of an int.Note that pAge is a variable like any of the variables.
-
A pointer whose value is zero is called a null pointer. All pointers, when they
are created, should be initialized to something. If you don't know what you want
to assign to the pointer, assign 0. A pointer that is not initialized
is called a wild pointer. Wild pointers are very dangerous. -
unsigned short int * pAge = &howOld; // make pointer to howOld
pAge is a pointer that now contains the address of the
howOld variable -
Indirection means accessing the value at the address held by a pointer.
The pointer provides an indirect way to get the value held at that address. -
The indirection operator (*) is also called the dereference
operator. When a pointer is dereferenced, the value at the address stored by the
pointer is retrieved. -
To assign the value in howOld to the new variable yourAge
by way of the pointer pAge, you would writeunsigned short int yourAge;
yourAge = *pAge;The indirection operator (*) in front of the variable pAge
means "the value stored at." This assignment says, "Take the value stored at the
address in pAge and assign it to yourAge." -
- Managing data on the free store.
- Accessing class member data and functions.
- Passing variables by reference to functions.
Pointers are used, most often, for three tasks:
- Managing data on the free store.
-
The stack is cleaned automatically when a function returns. All the local
variables go out of scope, and they are removed from the stack. The free store
is not cleaned until your program ends, and it is your responsibility to free
any memory that you've reserved when you are done with it. -
The advantage to the free store is that the memory you reserve remains
available until you explicitly free it. If you reserve memory on the free store
while in a function, the memory is still available when the function
returns.The advantage of accessing memory in this way, rather than using global
variables, is that only functions with access to the pointer have access to the
data. This provides a tightly controlled interface to that data, and it
eliminates the problem of one function changing that data in unexpected and
unanticipated ways.For this to work, you must be able to create a pointer to an area on the free
store and to pass that pointer among functions. -
You allocate memory on the free store in C++ by using the new keyword
-
new is followed by the type of the object that you want to allocate so
that the compiler knows how much memory is required -
The return value from new is a memory address. It must be assigned to a
pointer. -
unsigned short int * pPointer = new unsigned short int;
-
If new cannot create memory on the free store (memory is, after all,
a limited resource) it returns the null pointer. You must check your pointer for
null each time you request new memory. -
When you are finished with your area of memory, you must call delete on
the pointer. delete returns the memory to the free store. Remember that
the pointer itself--as opposed to the memory to which it points--is a local
variable. When the function in which it is declared returns, that pointer goes
out of scope and is lost. The memory allocated with new is not freed
automatically, however. That memory becomes unavailable--a situation called a
memory leak. It's called a memory leak because that memory can't be recovered
until the program ends. -
delete pPointer;
When you delete the pointer, what you are really doing is freeing up the
memory whose address is stored in the pointer. -
When you call
delete on a pointer, the memory it points to is freed.
Calling
delete on that pointer again will crash your program! When you delete a
pointer, set it to zero (null). Calling delete on a null pointer is
guaranteed to be safe. For example:Animal *pDog = new Animal; delete pDog; //frees the memory
pDog = 0; //sets pointer to null //... delete pDog; //harmless
-
9: int * pHeap = new int;
10: if (pHeap == NULL)
11: {
12: cout << "Error! No memory for pHeap!!";
13: return 0;
14: } -
19: delete pHeap;
20: pHeap = new int;
21: if (pHeap == NULL)
22: {
23: cout << "Error! No memory for pHeap!!";
24: return 0;
25: } -
28: delete pHeap;
29: return 0;
30: } -
Although line 28 is redundant (the end of the program would have returned
that memory) it is a good idea to free this memory explicitly. If the program
changes or is extended, it will be beneficial that this step was already taken
care of. -
Another way you might inadvertently create a memory leak is by reassigning
your pointer before deleting the memory to which it points. Consider this code
fragment:1: unsigned short int * pPointer = new unsigned short int;
2: *pPointer = 72;
3: pPointer = new unsigned short int;
4: *pPointer = 84; -
The code should have been written like this:
1: unsigned short int * pPointer = new unsigned short int;
2: *pPointer = 72;
3: delete pPointer;
4: pPointer = new unsigned short int;
5: *pPointer = 84; -
Just as you can create a pointer to an integer, you can create a pointer to any
object. -
Cat *pCat = new Cat;
This calls the default constructor--the constructor that takes no parameters.
The constructor is called whenever an object is created (on the stack or on the
free store). -
When you call delete on a pointer to an object on the free store, that
object's destructor is called before the memory is released. -
26 int main()
27 {
28 cout << "SimpleCat Frisky...\n";
29 SimpleCat Frisky;
30 cout << "SimpleCat *pRags = new SimpleCat...\n";
31 SimpleCat * pRags = new SimpleCat;
32 cout << "delete pRags...\n";
33 delete pRags;
34 cout << "Exiting, watch Frisky go...\n";
35 return 0;
36 }
Output: SimpleCat Frisky...
Constructor called.
SimpleCat *pRags = new SimpleCat..
Constructor called.
delete pRags...
Destructor called.
Exiting, watch Frisky go...
Destructor called. -
You accessed data members and functions by using the dot (.)
operator for Cat objects created locally. To access the Cat
object on the free store, you must dereference the pointer and call the dot
operator on the object pointed to by the pointer. Therefore, to access the
GetAge member function, you would write(*pRags).GetAge();
Parentheses are used to assure that pRags is dereferenced before
GetAge() is accessed.Because this is cumbersome, C++ provides a shorthand operator for indirect
access: the points-to operator (->), -
One or more of the data members of a class can be a pointer to an object on the
free store. The memory can be allocated in the class constructor or in one of
its methods, and it can be deleted in its destructor -
17: private:
18: int * itsAge;
19: int * itsWeight;
20: };
21:
22: SimpleCat::SimpleCat()
23: {
24: itsAge = new int(2);
25: itsWeight = new int(5);
26: }
27:
28: SimpleCat::~SimpleCat()
29: {
30: delete itsAge;
31: delete itsWeight;
32: } -
Every class member function has a hidden parameter: the this
pointer. this points to the individual object. Therefore, in each call
to GetAge() or SetAge(), the this pointer for the
object is included as a hidden parameter. -
The SetLength() and GetLength() accessor functions explicitly
use the this pointer to access the member variables of the
Rectangle object. The SetWidth and GetWidth accessors
do not. There is no difference in their behavior, although the syntax is easier
to understand.
If that were all there was to the this pointer, there
would be little point in bothering you with it. The this pointer,
however, is a pointer; it stores the memory address of an object. As such, it
can be a powerful tool. -
const int * pOne;
int * const pTwo;
const int * const pThree;pOne is a pointer to a constant integer. The value that is pointed
to can't be changed.pTwo is a constant pointer to an integer. The integer can be
changed, but pTwo can't point to anything else.pThree is a constant pointer to a constant integer. The value that
is pointed to can't be changed, and pThree can't be changed to point to
anything else. -
When a function is declared const, the compiler flags as an error any
attempt to change data in the object from within that function. -
If you declare a pointer to a const object, the only methods that you
can call with that pointer are const methods. -
8: public:
9: Rectangle();
10: ~Rectangle();
11: void SetLength(int length) { itsLength = length; }
12: int GetLength() const { return itsLength; }
13:
14: void SetWidth(int width) { itsWidth = width; }
15: int GetWidth() const { return itsWidth; } -
Output: pRect width: 5 feet
pConstRect width: 5 feet
pConstPtr width: 5 feet
pRect width: 10 feet
pConstRect width: 5 feet
pConstPtr width: 10 feet -
In line 41, pConstRect would be used, but it was declared to point to a
constant Rectangle. Therefore, it cannot legally call a
non-const member function; it is commented out. -
pConstPtr is declared to be a constant pointer to a rectangle. In
other words, the pointer is constant and cannot point to anything else, but the
rectangle is not constant. -
When you declare an object to be const, you are in effect declaring
that the this pointer is a pointer to a const object.
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
A while loop causes your program to repeat a sequence of statements as
long as the starting condition remains true. - 26 more annotations...
-
-
20: while (small < large && large > 0 && small < MAXSMALL)
21:
22: {
23: if (small % 5000 == 0) // write a dot every 5k lines
24: cout << ".";
25:
26: small++;
27:
28: large-=2;
29: } -
At times you'll want to return to the top of a while loop before the
entire set of statements in the while loop is executed. The continue
statement jumps back to the top of the loop. -
At other times, you may want to exit the loop before the exit conditions are met.
The break statement immediately exits the while loop, and program
execution resumes after the closing brace. -
26: while (small < large && large > 0 && small < 65535)
27:
28: {
29:
30: small++;
31:
32: if (small % skip == 0) // skip the decrement?
33: {
34: cout << "skipping on " << small << endl;
35: continue;
36: }
37:
38: if (large == target) // exact match for the target?
39: {
40: cout << "Target reached!";
41: break;
42: }
43:
44: large-=2;
45: } // end of while loop -
Both continue and break
should be used with caution. They are the next most dangerous commands after goto,
for much the same reason. Programs that suddenly change direction are harder to understand,
and liberal use of continue and break can render even a small while
loop unreadable. -
You
can create a loop that will never end by using the number 1 for the condition to
be tested. Since 1 is always true, the loop will never end, unless a break
statement is reached. -
10: while (1)
11: {
12: counter ++;
13: if (counter > 10)
14: break;
15: } -
The do...while loop executes the body of the loop before its condition
is tested and ensures that the body always executes at least one time -
11: do
12: {
13: cout << "Hello\n";
14: counter--;
15: } while (counter >0 ); -
A for loop combines three steps into one statement. The three steps are
initialization, test, and increment -
9: for (int i=0, j=0; i<3; i++, j++)
10: cout << "i: " << i << " j: " << j << endl; -
Any or all of the statements in a for loop can be null. To accomplish
this, use the semicolon to mark where the statement would have been. -
To create a for loop that acts exactly like a while loop,
leave out the first and third statements. -
10: for( ; counter < 5; )
11: {
12: counter++;
13: cout << "Looping! ";
14: } -
there are times when a
for(;;) loop or a while (1) loop is just what you'll want. -
So much can be done in the header of a for statement, there are times
you won't need the body to do anything at all. In that case, be sure to put a
null statement (;) as the body of the loop. -
8: for (int i = 0; i<5; cout << "i: " << i++ << endl)
9: ; -
Output: i: 0
i: 1
i: 2
i: 3
i: 4 -
It is important to note that counting variables created in the header of a
for loop are scoped to the outer block, not the inner block. The
implication of this is that if you have two for loops in the same
function, you must give them different counter variables, or they may interfere
with one another. -
30: for (n -= 3; n; n--)
-
This is a C++ idiom,
and is exactly equivalent to n != 0. This for loop relies on
the fact that when n reaches 0 it will evaluate
false, because 0 is false in C++. The for loop header
could have been written:for (n-=3; n>0; n++)
which might have been clearer. However, this idiom is so common in C++ that
there is little sense in fighting it. -
switch statements allow you to branch on any of a number of different
values. -
switch (choice)
{
choice 0:
choice 1:
choice 2:
cout << "Less than 3!";
break;
choice 3:
cout << "Equals 3!";
break;
default:
cout << "greater than 3!";
} -
The forever loop is used to put up a menu, solicit a choice from the user, act
on the choice, and then return to the menu. This will continue until the user
chooses to exit. -
Some programmers like to write
-
#define EVER ;;
for (EVER)
{
// statements...
}
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
The closer these variables correspond to reality, the easier it is to write the
program. - 34 more annotations...
-
-
You make a new type by declaring a class. A class is just a collection of
variables--often of different types--combined with a set of related
functions. -
One way to think about a car is as a collection of wheels, doors, seats,
windows, and so forth. Another way is to think about what a car can do: It can
move, speed up, slow down, stop, park, and so on. A class enables you to
encapsulate, or bundle, these various parts and various functions into one
collection, which is called an object. -
The functions in the class typically manipulate the member variables. They are
referred to as member functions or methods of the class. Methods of the
Car class might include Start() and Brake(). -
To declare a class,
-
class Cat
{
unsigned int itsAge;
unsigned int itsWeight;
Meow();
}; -
Declaring this class doesn't allocate memory for a Cat. It just tells
the compiler what a Cat is, what data it contains (itsAge and
itsWeight), and what it can do (Meow()). It also tells the
compiler how big a Cat is--that is, how much room the compiler must set
aside for each Cat that you create -
Some programmers like to prefix every class name with a particular letter--for
example, cCat or cPerson--whereas others put the name in all
uppercase or all lowercase. The convention that I use is to name all classes
with initial-capitalization, as in Cat and Person. -
You define an object of your new type just as you define an integer
variable:unsigned int GrossWeight; // define an unsigned integer
Cat Frisky; // define a Cat -
Once you define an actual Cat object--for example, Frisky--you use
the dot operator (.) to access the members of that object. Therefore,
to assign 50 to Frisky's Weight member variable, you would writeFrisky.Weight = 50;
In the same way, to call the Meow() function, you would write
Frisky.Meow();
When you use a class method, you call the method. In this example, you are
calling Meow() on Frisky. -
DON'T confuse a declaration with a definition. A declaration says what a
class is. A definition sets aside memory for an object. -
All members of a class--data and methods--are private by default. Private
members can be accessed only within methods of the class itself. Public members
can be accessed through any object of the class. This distinction is both
important and confusing. -
As a general rule of design, you should keep the member data of a class
private. Therefore, you must create public functions known as accessor methods
to set and get the private member variables. These accessor methods are the
member functions that other parts of your program call to get and set your
private member variables. -
1: // Cat class declaration
2: // Data members are private, public accessor methods
3: // mediate setting and getting the values of the private data
4:
5: class Cat
6: {
7: public:
8: // public accessors
9: unsigned int GetAge();
10: void SetAge(unsigned int Age);
11:
12: unsigned int GetWeight();
13: void SetWeight(unsigned int Weight);
14:
15: // public member functions
16: Meow();
17:
18: // private member data
19: private:
20: unsigned int itsAge;
21: unsigned int itsWeight;
22:
23: }; -
Declaring methods or data private enables the compiler to find programming
mistakes before they become bugs. -
Each accessor
function, along with any other class methods that you declare, must have an
implementation. The implementation is called the function definition.A member function definition begins with the name of the class, followed by
two colons, the name of the function, and its parameters -
6: class Cat // begin declaration of the class
7: {
8: public: // begin public section
9: int GetAge(); // accessor function
10: void SetAge (int age); // accessor function -
16: // GetAge, Public accessor function
17: // returns value of itsAge member
18: int Cat::GetAge()
19: {
20: return itsAge;
21: }
22:
23: // definition of SetAge, public
24: // accessor function
25: // returns sets itsAge member
26: void Cat::SetAge(int age)
27: {
28: // set member variable its age to
29: // value passed in by parameter age
30: itsAge = age;
31: } -
46: Cat Frisky;
47: Frisky.SetAge(5); -
50: cout << Frisky.GetAge() << " years old.\n";
-
If the constructor took one parameter, you would write
Cat Frisky (3);
In the event that the constructor takes no parameters at all, you leave off
the parentheses and writeCat Frisky ;
This is an exception to the rule that states all functions require
parentheses, even if they take no parameters. -
18: // constructor of Cat,
19: Cat::Cat(int initialAge)
20: {
21: itsAge = initialAge;
22: }
23:
24: Cat::~Cat() // destructor, takes no action
25: {
26: } -
58: Cat Frisky(5);
-
SetAge() cannot be const because it changes the member
variable itsAge. GetAge(), on the other hand, can and should
be const because it doesn't change the class at all. GetAge()
simply returns the current value of the member variable itsAge.
Therefore, the declaration of these functions should be written like this:void SetAge(int anAge);
int GetAge() const;If you declare a function to be const, and the implementation of
that function changes the object by changing the value of any of its members,
the compiler flags it as an error. -
Use const whenever possible. Declare member functions to be
const whenever they should not change the object. This lets the
compiler help you find errors; it's faster and less expensive than doing it
yourself. -
If you make GetAge() a const function--as you should--the
contract also promises that GetAge() won't change the Cat on
which it is called.C++ is strongly typed, which means that the compiler enforces these contracts
by giving you a compiler error when you violate them -
It is possible to run a program many times without going down every possible
code path. Thus, a run-time error can hide for quite a while. Compile-time
errors are found every time you compile. Thus, they are easier to identify and
fix. It is the goal of quality programming to ensure that the code has no
runtime bugs. One tried-and-true technique to accomplish this is to use the
compiler to catch your mistakes early in the development process. -
Like other functions, the definition of a class method has a function header
and a function body.The definition must be in a file that the compiler can find.
-
The convention that most programmers adopt is to put the declaration into what
is called a header file -
you put the declaration of the Cat class into a file named
CAT.HPP, and you put the definition of the class methods into a file
called CAT.CPP. You then attach the header file to the .CPP
file by putting the following code at the top of CAT.CPP:#include Cat.hpp
This tells the compiler to read CAT.HPP into the file, just as if
you had typed in its contents at this point. Why bother separating them if
you're just going to read them back in? Most of the time, clients of your class
don't care about the implementation specifics. Reading the header file tells
them everything they need to know; they can ignore the implementation files. -
Just as you can ask the compiler to make a regular function inline, you can
make class methods inline. The keyword inline appears before the return
value. The inline implementation of the GetWeight() function, for
example, looks like this:inline int Cat::GetWeight()
{
return itsWeight; // return the Weight data member
}You can also put the definition of a function into the declaration of the
class, which automatically makes that function inline. For example,class Cat
{
public:
int GetWeight() { return itsWeight; } // inline
void SetWeight(int aWeight);
};Note the syntax of the GetWeight() definition. The body of the
inline function begins im-mediately after the declaration of the class method;
there is no semicolon after the paren-theses. -
1: #include <iostream.h>
2: class Cat
3: {
4: public:
5: Cat (int initialAge);
6: ~Cat();
7: int GetAge() { return itsAge;} // inline!
8: void SetAge (int age) { itsAge = age;} // inline!
9: void Meow() { cout << "Meow.\n";} // inline!
10: private:
11: int itsAge;
12: }; -
1: // Demonstrates inline functions
2: // and inclusion of header files
3:
4: #include "cat.hpp" // be sure to include the header files!
5:
6:
7: Cat::Cat(int initialAge) //constructor
8: {
9: itsAge = initialAge;
10: }
11:
12: Cat::~Cat() //destructor, takes no action
13: {
14: } -
It is not uncommon to build up a complex class by declaring simpler classes and
including them in the declaration of the more complicated class. For example,
you might declare a wheel class, a motor class, a transmission class, and so
forth, and then combine them into a car class. -
You're probably wondering why two keywords do the same thing. This is an
accident of history. When C++ was developed, it was built as an extension of the
C language. C has structures, although C structures don't have class methods.
Bjarne Stroustrup, the creator of C++, built upon structs, but he
changed the name to class to represent the new, expanded functionality.
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
Whitespace (tabs, spaces, and newlines) is generally ignored in statements.
- 21 more annotations...
-
-
Any place you can put a single statement, you can put a compound statement, also
called a block. A block begins with an opening brace ({) and ends with
a closing brace (}). -
{
temp = a;
a = b;
b = temp;
}This block of code acts as one statement and swaps the values in the
variables a and b. -
Anything that evaluates to a value is an expression in C++. An expression is
said to return a value. -
An operator is a symbol that causes the compiler to take an action. Operators
act on operands, and in C++ all operands are expressions. -
The assignment operator (=) causes the operand on the left side of the
assignment operator to have its value changed to the value on the right side of
the assignment operator. -
There are five mathematical operators: addition (+), subtraction
(-), multiplication (*), division (/), and modulus
(%). -
myAge += 2;
The self-assigned addition operator (+=) adds the rvalue to the
lvalue and then reassigns the result into the lvalue. -
There are self-assigned subtraction (-=), division (/=),
multiplication (*=), and modulus (%=) operators as well. -
The increment operator (++) increases the value of the variable by 1
-
Both the increment operator (++) and the decrement
operator(--) come in two varieties: prefix and postfix. The prefix
variety is written before the variable name (++myAge); the postfix
variety is written after (myAge++). -
The semantics of prefix is this: Increment the value and then fetch it. The
semantics of postfix is different: Fetch the value and then increment the
original. -
This can be confusing at first, but if x is an integer whose value
is 5 and you writeint a = ++x;
you have told the compiler to increment x (making it 6) and
then fetch that value and assign it to a. Thus, a is now
6 and x is now 6. -
Every operator has a precedence value
-
Multiplication has higher precedence than addition
-
In C++, zero is considered false, and all other values are considered true
-
Table 4.2. The Logical Operators.
Operator Symbol Example AND && expression1 && expression2 OR || expression1 || expression2 NOT ! !expression -
A logical NOT statement evaluates true if the expression
being tested is false. Again, if the expression being tested is false, the value
of the test is TRUE! Thusif ( !(x == 5) )
is true only if x is not equal to 5. This is exactly the same as
writingif (x != 5)
-
if (x) // if x is true (nonzero)
-
if (!x) // if x is false (zero)
-
It is common to define your own enumerated Boolean (logical) type with
enum Bool {FALSE, TRUE};. This serves to set FALSE to
0 and TRUE to 1. -
The conditional operator (?:) is C++'s only ternary operator; that
is, it is the only operator to take three terms.The conditional operator takes three expressions and returns a value:
(expression1) ? (expression2) : (expression3)
This line is read as "If expression1 is true, return the value of
expression2; otherwise, return the value of expression3." Typically, this value
would be assigned to a variable.
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
determine the exact size of these types on your computer
- 21 more annotations...
-
-
sizeof(int) << " bytes.
-
Signed integers are either negative or positive. Unsigned
integers are always positive. -
Because you have the same number of bytes for both signed and
unsigned integers, the largest number you can store in an
unsigned integer is twice as big as the largest positive number you can
store in a signed integer. -
initialize
Width when you define it by writingunsigned short Width = 5;
-
It can become tedious, repetitious, and, most important, error-prone to keep
writing unsigned short int. C++ enables you to create an alias for this
phrase by using the keyword typedef, which stands for type
definition. -
1: // *****************
2: // Demonstrates typedef keyword
3: #include <iostream.h>
4:
5: typedef unsigned short int USHORT; //typedef defined
6:
7: void main()
8: {
9: USHORT Width = 5; -
If there is any chance that the value you'll want to put into your variable will
be too big for its type, use a larger type. -
If you need a larger number, you'll have to go to float or
double, and then you lose some precision. Floats and doubles can hold
extremely large numbers, but only the first 7 or 19 digits are significant on
most computers. That means that the number is rounded off after that many
digits. -
When an unsigned integer reaches its maximum value, it wraps around and
starts over, much as a car odometer might. -
A signed integer is different from an unsigned integer
-
When you run out of positive numbers, you run right into the largest negative
numbers and then count back down -
A char can be interpreted as a small number (0-255) or as a member of
the ASCII set -
In the ASCII code, the lowercase letter "a" is assigned the value 97.
-
there is a big difference between the value 5 and the character
`5'. The latter is actually valued at 53, much as the letter
`a' is valued at 97. -
4: for (int i = 32; i<128; i++)
5: cout << (char) i;
6: return 0;
7: }
Output: !"#$%G'()*+,./0123456789:;<>?@ABCDEFGHIJKLMNOP
_QRSTUVWXYZ[\]^'abcdefghijklmnopqrstuvwxyz<|>~s -
to define constants in C++:
const unsigned short int studentsPerClass = 15;
-
DON'T use the term int. Use short and long to
make it clear which size number you intended. -
Enumerated constants enable you to create new types and then to define variables
of those types whose values are restricted to a set of possible values. -
Every enumerated constant has an integer value. If you don't specify
otherwise, the first constant will have the value 0, and the rest will
count up from there. Any one of the constants can be initialized with a
particular value, however, and those that are not initialized will count upward
from the ones before them. Thus, if you writeenum Color { RED=100, BLUE, GREEN=500, WHITE, BLACK=700 };then RED will have the value 100; BLUE, the value
101; GREEN, the value 500; WHITE, the value
501; and BLACK, the value 700. -
It is important to realize that enumerator variables actually are of type
unsigned int, and that the enumerated constants equate to integer
variables. -
4: enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Â_Saturday };
5:
6: Days DayOff;
7: int x;
8:
9: cout << "What day would you like off (0-6)? ";
10: cin >> x;
11: DayOff = Days(x);
12:
13: if (DayOff == Sunday || DayOff == Saturday)
14: cout << "\nYou're already off on weekends!\n";
-
-
Teach Yourself C++ in 21 Days on 2009-11-21
-
For many years, the principle goal of computer programmers was to write short
pieces of code that would execute quickly. The program needed to be small,
because memory was expensive, and it needed to be fast, because processing power
was also expensive. As computers have become smaller, cheaper, and faster, and
as the cost of memory has fallen, these priorities have changed. Today the cost
of a programmer's time far outweighs the cost of most of the computers in use by
businesses. Well-written, easy-to-maintain code is at a premium. Easy-
to-maintain means that as business requirements change, the program can be
extended and enhanced without great expense. - 2 more annotations...
-
-
Object-oriented programming attempts to respond to these needs, providing
techniques for managing enormous complexity, achieving reuse of software
components, and coupling data with the tasks that manipulate that data.The essence of object-oriented programming is to treat data and the
procedures that act upon the data as a single "object"--a self-contained entity
with an identity and certain characteristics of its own. -
the four pillars of object-oriented development: encapsulation, data hiding,
inheritance, and polymorphism
-
More »
Groups
Diigo is about better ways to research, share and collaborate on information. Learn more »
Join Diigo