It is assumed that the user of this manual has access to a C compiler and understands the process of compiling and running programs. This manual provides only minimal coverage of I/O commands and provides no information on building user-interfaces.
The manual is organized into two main parts. In part I the commands and constructs of C are introduced. Statements have been organized according to the three classical control control structures: sequence, selection, and repetition. Basically, anything that doesn't fall under the categories of selection or repetition, is considered to be “sequence”. In part II some of the C++ extensions to C are introduced. C++ classes are the main feature of that section. This manual does not attempt to explain concepts of object-oriented programming beyond the what is necessary for understanding the syntax of using classes in C++. That is, classes are presented as “glorified” structs and not as a paradigm shift from structured programming to object-oriented programming.
One of the nice features about C is that there are many built-in facilities for manipulating strings, performing complex calculations, and handling the system clock. To be able to use many of these functionalities, you are required to “include” a header file where these are defined. Some common header files are given below:
math.h | provides mathematical functions such as power and ln |
stdio.h | basic I/O primitives such as scanf and printf |
stdlib.h | some useful and powerful tools such as qsort and rand |
time.h | ability to obtain and manipulate clock values (clock, time, etc.) |
string.h | string manipulation functions such as strcpy and strcat |
These header files are included in a program by putting the #include compiler directive at the beginning of the source code. WARNING: The # must be in the left-most column for it to be recognized as a compiler directive.
Example
This example shows how to include some common header files. Also notice the declaration of the main() function which where execution of a C program begins.
#include<stdio.h> #include<string.h> #include<math.h> void main() { . . . }
Note
Most commands in C are terminated with a semi-colon. The #include directives are NOT terminated with a semi-colon because they are “compiler directives” instead of “statements”.
Another Note
Identifiers in C are case-sensitive! That is, a variable named score is different from a variable named Score which is different that SCORE ...different than ScOrE ...
Example
This example shows both single- and multiple-line comments.
/*-------------------------------------------------- Programmer : Cher Last Modified: 28 Jul 1998 Description : This program ... --------------------------------------------------*/ . . . pi_are_square= pi * r * r; /* area of a round pie */
Type | Name | Memory | Approximate Range |
int | integer | 32 bits | -2.14 billion -- +2.14 billion |
float | real | 32 bits | 1.2E-38 -- 3.4E+38 |
double | real | 64 bits | 2.2E-308 -- 1.8E+308 |
char | char | 8 bits | 256 different characters |
Note
The mathematical functions that are found in math.h assume parameters will be of type double. Although variables of type float will be type cast automatically, it is conventional to use double unless there are severe memory limitations.
Another Note
Standard C handles boolean values as integers where a value of 0 is designated as false and non-zero values are true. C++ includes a bool type and constants false and true, but the implementation is with integers in the plain C fashion.
Example
To declare variables, list the type name followed by a list of identifiers. Notice that you can initialize variables at the declaration as with p and q. The other variables are uninitialized (i.e., who knows what they have in them!).
void main() { int a,b,c; /* three integer variables */ double x,y,z; /* three real-numbered variables */ char r; /* one character variable */ int p= 0, q= 12; /* mind your p's and q's */ . . . }
Warning 2.2
Floating point arithmetic (in any language) is only an approximation. For this reason, when dealing with monetary values it is a common practice to represent amounts in cents (i.e., integers) during calculations. The order of calculations can cause discrepancies in the values. The following code segment produced differing values for x and y even though the only difference is the order in which the calculations were performed.
#include<stdio.h> /* necessary for printf */ void main() { int i; float x,y; x= 0.0; y= 0.0; for (i=1; i<=1000; i++) x+= 100.0 / (float) (i * i); for (i=1000; i>=1; i--) y+= 100.0 / (float) (i * i); printf("%15.12f and %15.12f are ",x,y); if (x != y) printf("NOT "); printf("equal!\n"); }
The output of this program was:
164.393493652344 and 164.393463134766 are NOT equal!
%d | integer (decimal) |
%f | float or double |
%c | character |
%s | string |
Example
Here are some standard examples of using printf. The output is not terminated with a newline character, so it is necessary to explicitly place that character into the format string. This is done with backslash followed by n. Smart alecks inevitably want to know how to show the percent sign since it is used to specify a place holder; that is handled by placing two consecutive %'s in the format string as demonstrated below.
#include<stdio.h> int a=7; double z= 8.9; printf("I am %d years old\n",a); printf("I am %f%% sure you are NOT %d years old\n",z,a);
The example found in warning 2.2 demonstrates how to specify the number of decimal places (12 in that example) when displaying a floating point value.
Input from stdin (typically the keyboard) is accomplish with the scanf statement as follows:
The format string uses the same %-codes as the printf function. Often, a format string contains only a single code. This is followed by the address(es) of the variable(s) into which the typed value should be placed. For more information about addresses see section 5.3.
Another Example
Here are some standard examples of using scanf. This example also demonstrates the usage of an array of char's to create a “string”. The variable name represents the address of the string, so the & is not necessary.
#include<stdio.h> int age; double height; char name[80]; printf("Enter your age: "); scanf("%d",&age); printf("Enter your height (in feet): "); scanf("%f",&height); printf("Enter your name: "); scanf("%s",name);
* | multiplication |
/ | division |
% | modular division |
+ | addition |
- | subtraction |
Parentheses are used to override the default order of operations which follow the convention often taught and sometimes learned in algebra classes everywhere: multiplication and division first, then addition and subtraction, unless overridden by parentheses; ties are resolved from left to right.
The only “tricky” part has to do with variable types. When using / with integers, the result is always a truncated integer. The % operator always requires integer operands and can be used in conjunction with / to obtain a remainder along with its divisor (respectively). That is, 25 / 4 is 6 and 25 % 4 is 1.
If you want to mix integers and real numbers in a single expression you will need to type cast the integers to floating point values.
Example
Type casting is performed by specifying the type to be changed in parenthesis before the variable. In this example, b is type cast to be a double before it is used in the calculation. Notice that the assignment operator is a single =. This is in contrast to the == operator which is used when comparing two values as described in section 2.5.
int a=1,b=2,c; double x=1.1,y=2.2,z; a= a + 5*b; /* a= 11 */ z= (double) b * x + y; /* z= 3.3 */
Note
Some statements appear so often in programs that C has a shorthand notation for them. One example is the incrementing of a variable: i= i + 1. In C this can be written i++. The table below lists some common abbreviations. Keep in mind that there are equivalent operations for all of the arithmetic operators.
Shorthand Equivalent i++ i= i + 1 i- i= i - 1 i+= 5 i= i + 5 i/= x i= i / x
Another Note
The statement i++ can also be rendered ++i producing the same result. The former is the post-increment operator and the latter is the pre-increment operator. The difference in behavior only matter when the increment appears as part of a more complicated expression.
== | equal to |
!= | not equal to |
![]() |
greater than |
![]() |
less than |
![]() |
greater than or equal to |
![]() |
less than or equal to |
Examples of these operators are given in the discussion of if statements found in section 3.1.
Example
Notice that the condition being checked is placed within parentheses. The following statement will be performed if that condition evaluates to a non-zero value (and will be skipped if if the condition evaluates to a zero value). To perform multiple statements, the squiggley brackets ({}) are used to group the statements to be performed. The else keyword is optional.
#include<stdio.h> int a= 2,b= 5; if (a == 23) printf("They're equal!\n"); else printf("They're NOT equal!\n"); if (a <= b) { a*= b; printf("%d\n",a); /* what gets printed here? */ } if (a >= 100 && a <= 0) /* && means "and" ... why is this */ printf("Ha!\n"); /* probably a logical error? */ else printf("Ha!\n"); if (!a) /* what gets output here? */ printf("NOT a\n");
The || and && operators (“logical or” and “logical and” respectively) can be used to combine other boolean expressions into a more complex condition. The ! operator is the “logical negation” operator and precedes the expression to be not-ed.
Warning
The following statement is syntactically correct, but is often a logical error. Can you figure out why?
int a= 0; if (a = 7) printf("A is equal to 7\n");
Example
In this example, the user is asked to enter a TV channel number. A response is generated based on their choice. If the entered value is equal to 1 then “ABC” gets printed. If the value is 5, 6, or 7 then “Sci-Fi” gets printed. If 4 is selected then “FOXSci-Fi” gets printed. So what is the purpose of the break statement? The default option is, well, the default.
int channel; printf("Enter your favorite channel (integer): "); scanf("%d",&channel); switch(channel) { case 1 : printf("ABC"); break; case 2 : printf("NBC"); break; case 3 : printf("CBS"); break; case 4 : printf("FOX"); /* probably a mistake to */ case 5 : /* leave off the break */ case 6 : /* statement here */ case 7 : printf("Sci-Fi"); break; default: printf("What?"); }
initialization | the statement(s) to be performed upon entry into the loop |
condition | the condition to be checked each time through the loop; if the condition is true, the body of the loop is performed again |
updates | the value(s) to be updated each time through the loop |
loop-body | the statements to be performed each time through the loop |
Example
The initialization and updates can contain several statements (separated by commas). The condition can be simple or complex. Watch out for misplaced semicolons as in the last example.
The middle loop contains a few subtleties that are worth mentioning. First notice, that j is not declared. The keyword int in the loop initialization allows a previously undeclared variable to be introduced (works in C++ only). Also notice that the loop condition contains a reference to user before it gets initialized. In this case that is okay because of “short-circuit” evaluation of boolean expressions. Therefore, the variable user doesn't actually get referenced until after the user has entered a value for the first time.
#include<stdio.h> int i,user; for (i=0; i<10; i++) printf("%d\n",i); for (int j=0; j<10 || user; j++) { printf("%d\n",j*2); if (!(j < 9)) { printf("Enter 0 to quit, 1 to continue: "); scanf("%d",&user); } } user= 0; for (i=25; i>0; i/=5,user++) ; /* what does this do? */ printf("User: %d\n",user); /* i.e., what gets output? */
Example 4.2
The second loop will almost certainly produce unexpected results. What seems to be the problem with it?
#include<stdio.h> char choice; int num; num= 8; while (num < 20) { printf("We're bad!\n"); num+= 2; } while (choice == 'Y') /* got a problem here */ { printf("Do you want to continue looping? "); scanf("%c",&choice); }
Question
How could the last while loop in example 4.2 be changed to be a do-while loop to fix the problem?
Example
The values in brackets specify how many variables of the given type are to be reserved. Arrays in C are always indexed with integers starting at 0. Strings in C are simply arrays of characters. A string is terminated with a binary zero, so the most number of letters name could store below is 79 (plus the 0 character). Notice that strings and arrays of numbers are handled differently.
#include<stdio.h> #include<string.h> /* necessary for strlen */ int a[100],i,n; char name[80]; double values[1000],x; for (i=0; i<100; i++) /* Does this get ALL of them? */ a[i]= 0; printf("Enter your name: "); scanf("%s",name); /* no & needed */ printf("%s, your name has %d characters\n",name,strlen(name)); /* lets assume that values contains n pieces of data that have already been initialized. We'll find the average. */ x= 0.0; for (i=0; i<n; i++) x+= values[i]; printf("Average: %4.2f\n", x / (double) n);
After finishing this section you should be able to successfully finish exercise # 1. You may also be interested in seeing a summary of exercises.
Example
Each “piece” (field) of the structure is given a name and a type. Each field is then referenced by the variable name, a period, and the field name. A field can be a simple variable or an array. It is also possible to have an array of structures, as in the case of everyone. In this code segment, jack is initialized to be 35 units old with an id number of 12232. (His name, is, of course, Jack). fred is twice as old (and apparently joined the entity in question twice as late). everyone is either a replica of fred or jack. Which elements of everyone match jack?
#include<string.h> struct personInfo { int id; char name[80]; int age; } jack,fred,everyone[100]; jack.id= 12232; strcpy(jack.name,"Jack"); jack.age= 35; fred.id= 2*jack.id; strcpy(fred.name,"Fred"); fred.age= 2*jack.age; for (i=0; i<100; i++) /* do we need {}'s? */ if (i % 2) { everyone[i].id= jack.id; strcpy(everyone[i].name,"Jack"); everyone[i].age= jack.age; } else { everyone[i].id= fred.id; strcpy(everyone[i].name,"Fred"); everyone[i].age= fred.age; }
All addresses are of the same size, although some variables obviously take up more room than others. At any rate, keeping track of the location of a big variable has the same expense (4 bytes) as keeping track of the location of a small variable.
The * symbol is used to specify a pointer variable during declaration. This can be a bit confusing since * is used to mean multiplication in some contexts! Consider:
Example
Here aptr and bptr are given the same value (the address of a). Printing an address (%p stands for “pointer”) is about useless (except possibly for some debugging purposes), but as with many things in C, can be done. The * in the second printf takes on a third meaning: dereferencing. In that context, *aptr means “the value found at the address stored in aptr”. What value for *bptr gets output in this example?
int a=2,b=3; int *aptr, *bptr; aptr= &a; bptr= &a; /* this is "= &a" on purpose */ printf("The address of a is %p\n",aptr); printf("The value of a is %d\n",*aptr); a= 7; printf("The value at address in bptr is %d\n",*bptr);
There are two main reasons why one might want to use pointers: dynamic memory allocation and parameter passing. Parameter passing is discussed in section 6.2. For examples of dynamic memory allocation, keep reading!
Example
First notice the use of typedef. This is a matter of convenience.
Look at the pointer declarations for jack, fred, and everyone. All of them are declared to be pointers to structs. In the case of everyone we have an array of pointers to structs. To obtain memory in which to store the actual information, the malloc command can be used. The sizeof macro is used to determine how many bytes are necessary for storing the information. To use the new memory, we must dereference the pointer. The . operator is “stronger” than the * operator, so parentheses are required for grouping. This makes for rather cumbersome notation.
Pointers to structs is a fairly common phenomenon, so it is not surprising that C has a shortcut notation: the -> operator.
typedef struct personInfo PERSON; struct personInfo { int id; char name[80]; int age; }; PERSON *jack,*fred,*everyone[100]; jack= (PERSON *) malloc(sizeof(PERSON)); (*jack).id= 12232; strcpy((*jack).name,"Jack"); (*jack).age= 35; fred= (PERSON *) malloc(sizeof(PERSON)); fred->id= 12232; strcpy(fred->name,"Fred"); fred->age= 35; for (i=0; i<100; i++) { everyone[i]= (PERSON *) malloc(sizeof(PERSON)); everyone[i]->id= jack->id; strcpy(everyone[i]->name,"Jack"); everyone[i]->age= jack->age; }
The natural question: WHY?!?! Suppose you may need to store anywhere from 1 to 100000 variables of type PERSON as in the previous example. It would be “wasteful” in terms of memory usage to have an array of 100000 variables, each of which require 88 bytes. Instead you can have an array of 100000 variables, each containing 4 bytes (i.e., pointers) and simply allocate the additional memory as needed.
It should also be mentioned that a number of data structures such as linked lists and trees are most intuitively represented using pointers as well.
Note
In the previous example we saw how to dynamically allocate memory at run-time. How do we deallocate memory? Assuming the same declarations above, to deallocate the memory allocated for fred, this statement will suffice: free(fred).
In C, subprograms are called functions. Before main(), a prototype of all functions must be given. The prototype describes what the interface of the function looks like. The keyword void preceding both the prototype and the actual function definition, specifies the return value of the function. In this case, the function doesn't return any information, so the return value is set to void.
Example
#include<stdio.h> void hitReturn(); /* a "prototype" */ void main() { /* do some stuff */ hitReturn(); /* do some other stuff */ hitReturn(); /* finish up everything */ hitReturn(); } void hitReturn() { char result[3]; printf("\n\n-----------------------------------------------\n"); printf("Hit <Return> to Continue"); fgets(result,3,stdin); }
Example
This subprogram has one parameter (a string). The value of the parameter passed to the function depends on the condition causing the error. Thus, the error message is customized to the error condition.
#include<stdio.h> void reportError(char msg[]); void main() { /* some stuff */ if (something_bad_happens) reportError("Something Bad Happened!"); if (something_awful_happens) reportError("Something Awful Happened!"); if (running_Windows98) reportError("Crashed for Apparently no Reason!"); . . . } void reportError(char msg[]) { printf("ERROR: %s\n",msg); abort(); /* exits program immediately/ugly */ }
Another Example
The source code for this example is available in subpgm.c This extended example demonstrates several concepts such as the use of local variables, declaring functions that return values, and passing addresses (pointers) as parameters. For examples demonstrating the role of pointers as parameters see section 7.3.
Function calcAvg returns the average age of n people as a double. The function getPersonInfo allows the user to input a name an age for a person. It also updates the value of n and assigns and id number based on the order of entry. It is necessary to pass the address of n in this case because, by default C parameters are passed by value. That is, the parameter is a copy of the original. When passing an address, the parameter is a copy of an address. By dereferencing the address (copy), the original data is accessible.
#include<stdio.h> typedef struct personInfo PERSON; struct personInfo { int id; char name[80]; int age; }; double calcAvg(PERSON *[],int); void getPersonInfo(PERSON *, int *); void main() { PERSON *people[100]; int i,n; double avg; n= 0; for (i=0; i<3; i++) { people[i]= (PERSON *) malloc(sizeof(PERSON)); getPersonInfo(people[i],&n); } avg= calcAvg(people,n); printf("Average age is: %3.1f\n",avg); } double calcAvg(PERSON *everyone[],int n) { int i; double tot; tot= 0.0; for (i=0; i<n; i++) tot+= (double) everyone[i]->age; return tot / (double) n; } void getPersonInfo(PERSON *p, int *n) { printf("Enter age: "); scanf("%d",&(p->age)); printf("Enter name: "); scanf("%s",p->name); (*n)++; p->id= 10000+(*n); }
Note
Array names are, in fact, pointers. Therefore, when an array is passed as a parameter, the address of the array is made available to the subprogram. Therefore, it is NOT necessary to explicitly pass the address of an array.After finishing this section you should be able to successfully finish exercise # 2. You may also be interested in seeing a summary of exercises.
Example
This methods of commenting is more convenient in many cases and can be nested within the C-style /* */ comments.
int age; // the age of the monkey int IQ; // the IQ of the monkey
Example
The cout object is used for output and the cin object is used for input. Notice that it is not necessary to tell these objects what kind of data are being used ...they know how to handle it properly. The identifier endl produces the newline character.
#include <iostream.h> void main() { char name[80]; cout << "I want to see some output!\n"; cout << "What is your name: "; cin >> name; cout << "Good to see you " << name << "!" << endl; }
Example (Doesn't Work)
In this program, the program presumably wants to have the user enter a value and store that number (plus one) into the parameter that was passed. C always passes parameters by value2 so the changes made to num in getNum are being made to a copy of the parameter n. When the value for n gets printed, there is no change.
#include<stdio.h> void getNum(int); void main() { int n; getNum(n); printf("Num: %d\n",n); } void getNum(int num) { printf("Enter value: "); scanf("%d",&num); num++; }
Example (C Fix)
The problem with the first example is fixed by passing the address of n as a parameter. Thus changes are made to the original value. The “problem” with this method is not that it doesn't work, but simply that the change of notation within the function getNum is somewhat annoying.
#include<stdio.h> void getNum(int *); void main() { int n; getNum(&n); printf("Num: %d\n",n); } void getNum(int *num) { printf("Enter value: "); scanf("%d",num); (*num)++; }
Example (C++ Fix)
This version of the program allows the programmer to keep the same notation as in the original example, but still passes the parameter by reference, causing the program to perform as intended. That is, the ampersand (&) is simply a flag in the parameter list that tells the compiler to pass the parameter by reference (variable) instead of by value.
#include<stdio.h> void getNum(int &); void main() { int n; getNum(n); printf("Num: %d\n",n); } void getNum(int &num) { printf("Enter value: "); scanf("%d",&num); num++; }
Note
When passing a large structure (or an object as we will see in section 8), it is often desireable to pass the address so that it is not necessary to copy the entire variable on each function call. Of course, passing a parameter by reference implies that the variable will be modified by the subprogram. To prevent modification of the parameter while maintaining the efficiency of passing by reference, use the keyword const in the function declaration as follows:
void myfunc(bigType const &bigVar) . . .
After finishing this section you should be able to successfully finish exercise # 3. You may also be interested in seeing a summary of exercises.
A structure allows the programmer to combine variables of different types into a single big variable. A class allows the programmer to combine variables of different types and functions into a single big variable called an object.
class | a declaration of a special variable that can combine variables and functions together in a single big variable |
object | an instance of a class (i.e., an actual variable, not just a type definition) |
member function | a function that is part of a class |
inheritance | variables and/or functions that are passed from one class to another |
Example
The source code for this example is available in dice1.cpp This example shows the class declarations necessary to produce a “plain” 6-sided die. Each class has a constructor and a destructor. The constructor is a function that is called each time an instance of the class is created. Conversely, the destructor is a function that is called each time an instance of the class is destroyed. Neither of these special functions has a return value. The constructor always bears the name of the class and the destructor always bears the name of the class preceded by the tilde.
The variable currentValue is declared as a protected integer. “Protected” means that it cannot be accessed from outside the class. That is, the internal functions roll and value are the only functions that are allowed to access its value. This prevents a rogue programmer from assigning an invalid value to the die. It is the job of the function value to return the value of currentValue so that other parts of the program can view it. The roll function is currently the only entity besides the constructor that changes the value of currentValue. It uses the rand function found in stdlib.h to assign a value in the proper range.
PlainDie is a class and die1 and die2 are instances of the class (i.e., objects). Note the “structure-like” notation used to access the functions of each object. What do you think would happen if the following line were inserted into the program right before the for loop: cout « die1.currentValue;?
#include <iostream.h> #include <stdlib.h> #include <time.h> class PlainDie { public: PlainDie(); ~PlainDie(); void roll(); int value() { return currentValue; }; protected: int currentValue; }; void main() { int i; PlainDie die1,die2; for (i=0; i<10; i++) { cout << "Die 1: " << die1.value(); cout << "\t Die 2: " << die2.value() << "\n"; die1.roll(); die2.roll(); } } PlainDie::PlainDie() { srand( (unsigned)time( NULL ) ); roll(); } PlainDie::~PlainDie() { } void PlainDie::roll() { currentValue= rand() % 6 + 1; }
The output of this program is as follows:
Die 1: 4 Die 2: 4 Die 1: 4 Die 2: 1 Die 1: 4 Die 2: 1 Die 1: 6 Die 2: 1 Die 1: 6 Die 2: 3 Die 1: 5 Die 2: 1 Die 1: 6 Die 2: 3 Die 1: 3 Die 2: 4 Die 1: 3 Die 2: 3 Die 1: 1 Die 2: 3
Example
The source code for this example is available in dice2.cpp This example demonstrates the use of inheritance to produce an enhanced class called Die. This class inherits all of the functionality of PlainDie, but overrides the definition of roll and adds a new protected variable called numberOfSides. Notice that the definition of PlainDie is unchanged.
This example also demonstrates that one can use pointers to objects much in the same way as pointers to structures. One difference is the C++ new operator that makes allocation much simpler.
Notice that the constructor for Die calls the constructor for PlainDie. That is included in this example to demonstrate that it can be done. Usually that is a good way simplify a constructor. One problem with doing that in this case is that the roll function belonging to PlainDie gets called at initialization instead of of the newly defined roll function. To compensate for this roll gets called again in the Die constructor.
Another flaw with this method is that placing the srand command inside the constructor means that all die objects created within a given second will have the same initial value generated.
#include <iostream.h> #include <stdlib.h> #include <time.h> class PlainDie // same as before { public: PlainDie(); ~PlainDie(); void roll(); int value() { return currentValue; }; protected: int currentValue; }; class Die : public PlainDie // inherits from PlainDie { public: Die(int = 6); // 6 sides by default ~Die(); void roll(); int sides() { return numberOfSides; }; protected: int numberOfSides; }; void main() { int i; PlainDie die1; Die *die2; Die die3(12); die2= new Die(8); cout << "Die #1 has 6 sides\n"; cout << "Die #2 has " << die2->sides() << " sides\n"; cout << "Die #3 has " << die3.sides() << " sides\n"; cout << "------------------------------------------\n"; for (i=0; i<10; i++) { cout << "Die 1: " << die1.value(); cout << "\t Die 2: " << die2->value(); cout << "\t Die 3: " << die3.value() << "\n"; die1.roll(); die2->roll(); die3.roll(); } delete die2; } PlainDie::PlainDie() { srand( (unsigned)time( NULL ) ); roll(); } PlainDie::~PlainDie() { } Die::Die(int numSides) : PlainDie() { numberOfSides= numSides; roll(); } Die::~Die() { } void PlainDie::roll() { currentValue= rand() % 6 + 1; } void Die::roll() { currentValue= rand() % numberOfSides + 1; }
The output of this program is as follows:
Die #1 has 6 sides Die #2 has 8 sides Die #3 has 12 sides ------------------------------------------ Die 1: 1 Die 2: 2 Die 3: 10 Die 1: 5 Die 2: 8 Die 3: 10 Die 1: 1 Die 2: 3 Die 3: 1 Die 1: 6 Die 2: 8 Die 3: 3 Die 1: 1 Die 2: 4 Die 3: 11 Die 1: 4 Die 2: 2 Die 3: 5 Die 1: 2 Die 2: 3 Die 3: 1 Die 1: 1 Die 2: 2 Die 3: 12 Die 1: 5 Die 2: 5 Die 3: 5 Die 1: 4 Die 2: 2 Die 3: 3
After finishing this section you should be able to successfully finish exercise # 4. You may also be interested in seeing a summary of exercises.
Suppose you have two dice die1 and die2 and you need to store the sum of their values into a variable called sum. This could be accomplished easily as follows:
sum= die1.value() + die2.value();
Of course, if you are constantly adding values of dice together in your program it would be nicer (and perhaps more intuitive) to simply say:
sum= die1 + die2;
For this method to work properly, you will have to redefine the meaning of the “+” operator when used with dice.
Example (Overloading + and ==)
In this example we show how to add values of dice with “+” and how to compare values of dice with “==”. This example assume the same definition of PlainDie as in section 8.3 with the following additions:
class PlainDie { public: int operator+(PlainDie die) { return currentValue + die.value(); }; int operator==(PlainDie die) { return currentValue==die.value(); }; . . . } void main() { Die die1,die2; sum= die1+die2; . . . }
Another kind of operator overloading can take the form of the so-called “stream insertion operator” (i.e., “«”). If there is some standard way you want an object to be displayed, you can overload this operator so that it will produce output in the proper form without having to redo it every time.
Example (Overloading «)
Suppose you want to have the statement: cout « die1; to produce the following output: Sides: 6, Value: 4 (where 6 and 4 are numberOfSides and currentValue, respectively. First overload the “«” operator and then you're in business.
This example also demonstrates the use of a “friend” function. A friend function is declared outside of the class, but is allowed to access protected members of that class. In this example we assume that the definition of Die is the same as in section 8.3 except for the following addition:
class Die { public: friend ostream &operator<<(ostream &, Die); . . . } void main() { Die mydie; cout << mydie; } ostream &operator<<(ostream &output, Die die) { output << "Sides: " << die.sides(); output << ", Value: " << die.value() << endl; }
After finishing this section you should be able to successfully finish exercise # 4. You may also be interested in seeing a summary of exercises.
This document was generated using the LaTeX2HTML translator Version 2018 (Released Feb 1, 2018)
Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds. Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.
The command line arguments were: latex2html -nonavigation -address 0 -t 'C and C++ Syntax' -up_url ../../ -up_title 'Terry Sergeant's Homepage' -split 1 -dir ../web/cmanual cmanual
The translation was initiated on 2020-09-03