0% found this document useful (0 votes)
18 views

C++ Notes

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

C++ Notes

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 567

Learning Objectives: Printing

Use the cout command to write text to the console

Add a newline character by using the endl command

Create single-line and multi-line comments by using //


and /* */ respectively
Printing to the Console

Printing to the Console


As you learn C++, you will write code in the text editor to the left. There is
already some code there that we will cover later. For now, use a cout
command to see the output of your program. Copy and paste the code
below into the text editor on the left. Make sure your code is in between the
//add code below this line and //add code above this line comments.
Then click the TRY IT button to see what is outputted by the code.

cout << "Hello world!";

The reason you were able to see the words appear is because of the cout
command followed by the << and finally what you want to print "Hello
world";. cout is short for characters out and is used to output your desired
text.

Change your desired output to look like this and TRY IT again.

"My name is Codio."


Printing

Printing without the Newline Character


The cout command does not add a newline character. The code below will
print the two words on the same line without a space. Copy the code below
into the text editor on the left and then click the TRY IT button below to see
the output.

cout << "Hello";


cout << "world!";

Adding the Newline Character


The text in red shows the endl command which adds the newline
character. (The newline character is what is inserted when you press
“Enter” or “Return”).

.guides/img/NewlineCharacter

Add a second line by using the cout << endl; command under "cout <<
"world!";. Then enter the ouput command to print My name is Codio.
Finally, click the TRY IT button to see the resulting output.

cout << "Hello";


cout << "world!";
cout << endl;
cout << "My name is Codio." << endl;
challenge

What happens if you:


Add a space after Hello and before the closing "
Add << endl; after cout << "Hello ";
Delete cout << endl; under cout << "world!";
Comments

Comments
You may have wondered why a couple of lines of code are a different color
(in the below example, light brown, but it depends on the Theme you have
picked):

.guides/img/Comment

In C++, to write notes in code without affecting its function, we can use //
to make a single-line comment. Click the TRY IT button below to see the
resulting output.

Comments can also be used to help you fix your code. You can “comment
out” lines of code that are not working or you suspect are causing
problems.

challenge

What happens if you:


Change cout << "Red" to cut << "Red"
Add // in front of cut << "Red"

Block Comments
To make a block comment you can either make multiple single-line
comments using // or wrap the set of lines in /* and */. TRY IT below!
/*
This is the start of a multi-line comment.
You can end the comment with a star(*) followed by a forward
slash(/).
*/

//You can also do a multi-line comment


//like this!

cout << "Notice how the comments above are lightly faded.";
cout << "Most IDEs automatically lighten the comments.";
cout << "This is a common feature known as syntax
highlighting.";

What is an IDE?
An integrated development environment, or IDE, is a computer program that
makes it easier to write other computer programs. They are used by
computer programmers to edit source code, and can be easier to use than
other text editors for new programmers. They can have compilers so
programmers don’t have to open other programs to compile the source code.
They also often have syntax highlighting. … It also may have predictive
coding that can finish lines with syntax such as brackets or semicolons and
can suggest variables to be used. It also may have debuggers that can step
through lines, take breaks and inspect variables.
Source: Simple Wikipedia
Learning Objectives: Variables

Understand the rules of naming a variable

Assign/overwrite a value to a variable

Understand four basic data types: integers (ints), floats,


boolean (bool), and strings
Variables

What Is a Variable?
In computer science, we often need to use data. Variables are used to store
a value for a particular type of data.

Each variable in C++ has:

1. a data type
2. a name
3. a value

We will discuss each of these parts over the rest of this reading assignment.

Three Actions for Variables


There are a few different actions taken involving variables:
1. Declaring - when you set or declare the data type and name of the
variable. These two properties of a variable do not change.
1. Assigning - when you set the value of the variable. The value of a
variable can change.
1. Accessing - when you retrieve the value of the variable by calling its
name.

You must declare and assign a variable before you can access it.

Take a look at the visualizer on the left to see an example of how this
works. Click on the Forward > button at the bottom of the page to
repeatedly move through each stage of the process. The visualizer may take
a few seconds to load. Click on the Refresh code button in the upper left
corner if you encounter an error message.
Data Types: Integers

Integers
Integers (often called ints) are whole numbers. They can be positive or
negative. Do not use a comma when typing large numbers.

Copy the code below into the text editor. Then click the TRY IT button.

int number;
number = 50;
cout << number << endl;

Next, let’s modify the code to look like what’s below and then click the TRY
IT button again.

int number = 50;


cout << number << endl;

important

You may have noticed that we can declare a variable name and assign
it a value all in one step by using int number = 50; instead of int
number; followed by number = 50;. Both ways will produce the same
result.

5 vs. “5”
5 is not the same thing as “5”. The first one is an integer, the second is a
string. You will see in a later lesson the different operations you can
perform on strings and numbers. Treating a string as a number can cause
errors.
challenge

What happens if you:


Change the variable to 5000?
Change the variable to 5,000?
Change the variable to 050?
Change the variable to "5000" (with double quotes)?
Data Types: Floating Point
Numbers

Floating Point Numbers


Floating point numbers (often called floats) are numbers with a decimal.
They can be positive or negative. Copy the code below and TRY IT.

double decimal = 0.5;


cout << decimal << endl;

Why Use Double Instead of Float?


In C++, there is a data type called float, but as it only uses 4 bytes, it is
insufficient for most math. Instead, we use double which uses 8 bytes or
double the space of a float.

challenge

What happens if you:


Change the variable to 50.?
Change the variable to .001?
Data Types: Boolean

Boolean
A boolean variable (declared as a bool) can only take on the value of true
or false. You will see how boolean values are used when we talk about
conditionals and while loops. Copy the code below and TRY IT.

bool thisIsFun = true;


cout << boolalpha << thisIsFun << endl;

challenge

What happens if you:


Change the variable to false?
Remove the boolalpha << command?
Change the variable to True?
Change the variable to False?
Change the variable to TRUE?

important

You may have noticed that printing a boolean of true resulted in a 1


and a boolean of false resulted in a 0 when you remove the boolalpha
<< command. In C++, the boolean value of true is associated with the
integer 1 while the boolean value of false is associated with the integer
0. Assigning the value of uppercase True or False to a boolean variable
will cause an error message to appear.
Data Types: Strings

Strings
A string is a collection of text, numbers, or symbols. Strings are always
surrounded by quotation marks. Copy the code below and TRY IT.

string words = "This is a string.";


cout << words << endl;

challenge

What happens if you:


Forget one of the " quotation marks?
Forget both " " quotation marks?
Use single (') quotation marks?
Use uppercase String instead of lowercase string?

Notice that when you print a string, the quotation marks are not printed.
Declaring Variables

Declaring a Variable
Declaring a variable has two parts - setting or declaring the data type and
the name of the variable. These two properties of a variable do not change.

To declare a variable, type the data type and name of the variable you want
to create, and a ; (semi-colon). Copy the code below and TRY IT.

string my_var;

You will notice we are not printing anything - that is because no value has
been assigned yet. Thus, the message Command was successfully executed.
appears when you click on the TRY IT button. The declaration step only sets
aside empty memory.

challenge

What happens if you:


Create two variables with the same type and name?
Create two variables with the same name but different
capitalization (i.e. my_var and My_var)?
Create two variables of different types with the same name?

Variable Naming Rules


Here are the rules for naming a variable.

Rule Correct Incorrect


Start with a
letter or variable, _variable 1variable
underscore
Remainder
of variable
name is
letters, var_i_able, var1able var-i-able, var!able
numbers, or
underscores
Cannot use a
my_class class
C++ keyword
Variables variable, Variable, and
are case VARIABLE are all
sensitive different variables

What Are C++ Key Words?


C++ keys words are words that are reserved for specific functions or tasks
within C++ programs. These words cannot be used to name variables and
will result in errors if they are not handled correctly. Click below to see a
list of C++ key words.

List of C++ key words

and and_eq asm auto bitand


bitor bool break case catch
char class compl const const_cast
continue default delete do double
dynamic_cast else enum explicit extern
false float for friend goto
if inline int long mutable
namespace new not not_eq operator
or or_eq private protected pubic
register reinterpret_cast return short signed
sizeof static static_cast struct switch
template this throw true try
typedef typeid typename union unsigned
using virtual void volatile wchar_t
while xor xor_eq
Initializing, Assigning, and
Assessing

Initializing & Assigning Values


We call the process of setting the initial value of a variable initialization.
Recall that you can do this separately after the declaration or combine it
into the same statement as the declaration.

.guides/img/VariableAssignmentInt

Since the value stored in a variable can change, we call changing the value
assigning or re-assigning. Use the assignment operator, =, to give a
variable a new value.

Accessing Variables
Copy the code below and TRY IT to see the results of the cout commands.
Click on the ++Code Visualizer++ link to see how the value of my_int
changes.

int my_int = 123;


cout << my_int << endl;
my_int = 321;
cout << my_int << endl;

When we use a variable’s name to get the value like in the cout statements
above, we say we are accessing the variable.

Code Visualizer
Lab: Printing

Tutorial Lab 1: Printing


1. In the text editor to your left, you will see the code below:

string my_var = "I am learning"; //step 1


cout << my_var; //step 2
my_var = " to program"; //step 3
cout << my_var; //step 4
my_var = " in C++."; //step 5
cout << my_var << endl; //step 6
my_var = "Hooray!"; //step 7
cout << my_var; //step 8

2. Click TRY IT to see what the code outputs.

3. Click on the ++underlined++ text below to highlight some of the


important points in the code:

Step 1 - Declare the variable my_var and initialize it to the value I am


learning
Step 2 - Print without a new line character by not including << endl;
Step 3 - Add a space when starting the string to avoid printing
learningto
Step 6 - A newline character is added using << endl;
Step 8 - Hooray! is on its own line since the << endl; command was
used in step 6

4. To remove the highlighting, click here: Remove Highlighting


Lab: Variables

Tutorial Lab 2: Variables


1. Use the text editor to the left.

2. Copy the code below.

int one = 1;
int two = 2;
int three = 3;
int four = 4;

two = one;
three = two;
four = three;

cout << four;

3. TRY IT to see the output. Click on the ++Code Visualizer++ link below to
go through the program step by step.

Code Visualizer
Lab: Challenge

Tutorial Lab 3: Fundamentals Challenge


In the code to the left, we see that there are a series of declared and
initialized variables. Use these variables along with the cout << and <<
endl; commands to print out a custom message to customers who open a
chat client.

Your output should look something like this:

Hello! Today is Wednesday, May 4.


The current wait time is 4 minutes.

The pattern is as follows. The * indicates variables:

*greeting* Today is *dayOfWeek*, *month* *day*.


The current wait time is *currentWaitMinutes* minutes.

To test the code, first click on the COMPILE button. This will compile your
code and turn it into a program. If your program compiled successfully, you
will see the message Command was successfully executed. Then you can
run your program by clicking on the TEST buttons. You will see the output
of a few different test cases:

Take a look at the test outputs above. Do they look like the expected outputs
below? If not, your code may need some revision.

Hello! Today is Monday, July 4.


The current wait time is 9 minutes.

Howdy! Today is Tuesday, December 15.


The current wait time is 2 minutes.

Greetings! Today is Friday, March 13.


The current wait time is 39 minutes.
Learning Objectives: Arithmetic
Operators

Recognize the symbols for arithmetic operators

Use the printf() command to print doubles and integers

Demonstrate how to increment and decrement a


variable

Perform string concatenation

Apply PEMDAS rules to arithmetic operations


Addition

The Addition (+) Operator


The addition operator works as you would expect with numbers. Copy and
paste the code below into the text editor on the left. Make sure your code is
in between the //add code below this line and //add code above this
line comments. Then click the TRY IT button to see what is outputted by
the code.

cout << 7 + 3 << endl;

You can also add two variables together. Modify the code to look like what’s
below and then click the TRY IT button again.

int a = 7;
int b = 3;
cout << a + b << endl;

challenge

What happens if you:


Make a of type double (e.g. double a = 7.0;)?
Change a to double a = 7.1;?
Make b a negative number (e.g. int b = -3;)?
Make b an explicitly positive number (e.g. int b = +3;)?
important

IMPORTANT
You may have noticed that when you add an int of 3 to a double of 7.1
you get 10.1. However, when you add an int of 3 to a double of 7.0, you
get 10 instead of 10.0. This occurs because by default cout does not
print zeros after a decimal point unless those zeros are enclosed by
other non-zero digits.

Examples:
* cout << 7 + 3.14; prints 10.14
* cout << 7.0 + 3.00; prints 10
* cout << 7.00 + 3.01400; prints 10.014

==Note== that when an int and a double are added together, the result
will be a double because the program will take on the data type that is
more flexible.
Printing Floating Point Numbers

cout
The cout command is considered to be non-specific because you can use the
same syntax for all of your printing needs (e.g. cout << 1;, cout <<
"Hello";, and cout << true;). However, for printing certain numbers, it is
not always clear if what’s printed is an int or a double sometimes.

int a = 1;
double b = 1.0;
cout << a << endl;
cout << b << endl;

Even though you are printing a double of 1.0, the system will disregard the
decimal and the trailing zero when cout is used. There is another print
command called printf() that also prints text to the console.

printf()
printf() originates from the C language and, unlike the cout command, it
is considered to be specific. This means that you must specify what type of
data you want to print before you can use the command successfully.

int a = 1;
double b = 1.0;
cout << a << endl;
cout << b << endl;
printf("%d \n", a);
printf("%f \n", b);
challenge

What happens if you:


Remove the \n from printf("%d \n", a);?
Replace %d with %f in printf("%d \n", a);?
Replace %f with %d in printf("%f \n", b);?

important

IMPORTANT
When printf() is used, a specifier is needed in order to tell the system
what type of data you want to print. The %d tells the system to print an
integer and %f tells the system to print a floating point number. If you
use an incorrect specifier, you will receive an error message. By
default, floating point numbers contain six zeros after the decimal
point if they are printed using printf().

The \n in printf() is equivalent to endl. They both print a newline


character. Removing the \n from printf("%d \n", a); will delete the
newline character and cause the variables a and b to be printed side-
by-side.

cout vs. printf()


Unless you want to be specific with how your data is printed, you should
always default to using cout. Only use printf() when formatting is
important.
Incrementing Variables

Incrementing Variables
Incrementing a variable means to increase the value of a variable by a set
amount. The most common incrementation you will see is when a variable
increments itself by the value of 1.

int a = 0;
a = a + 1;
cout << a << endl;

How to Read a = a + 1
The variable a appears twice on the same line of code. But each instance of
a refers to something different.

.guides/img/Increment

The ++ and += Operators


Since incrementing is such a common task for programmers, many
programming languages have developed a shorthand for a = a + 1. The
result is a++ which does the same thing as a = a + 1.

int a = 0;
int b = 0;
a = a + 1;
b++;
cout << a << endl;
cout << b << endl;
In the cases where you need to increment by a different number, you can
specify it by using the += operator. You can replace b++; with b+=1; in the
code above and still get the same result.

challenge

What happens if you:


Replace b++ in the code above with b+=2?
Replace b++ in the code above with b+=-1?
Replace b++ in the code above with b-=1?
String Concatenation

String Concatenation
String concatenation is the act of combining two strings together. This is
done with the + operator.

string a = "This is an ";


string b = "example string";
string c = a + b;
cout << c << endl;

challenge

What happens if you:


Concatenate two strings without an extra space (e.g. remove the
space after an in string a = "This is an";)?
Use the += operator instead of the + operator (e.g. a+=b instead of a
+ b)?
Add 3 to a string (e.g. string c = a + b + 3;)?
Add "3" to a string (e.g. string c = a + b + "3";)?
Subtraction

Subtraction
Copy the code below and TRY IT.

int a = 10;
int b = 3;
int c = a - b;
cout << c << endl;

challenge

What happens if you:


Assign b to -3?
Assign c to a - -b?
Assign b to 3.1?
Change b to bool b = true;?

important

IMPORTANT
Did you notice that you were able to subtract a bool from an int?
Recall that a bool of true is actually an integer of 1 and false is actually
0. Thus, the system is able to add and subtract bools and ints. In
addition, assigning b which is of type int to 3.1 will force the variable
to adopt the integer value of 3 instead. Remember that all ints
disregard decimal places.

The -- and -= Operators


Decrementing is the opposite of incrementing. Just like you can increment
with ++, you can decrement using --.
int a = 10;
a--;
cout << a << endl;

Like +=, there is a shorthand for decrementing a variable, -=. For example,
if you want to decrement the variable a by 2 instead of 1, replace a-- with
a-=2.

Subtraction and Strings


You might be able to concatenate strings with the + operator, but you
cannot use the - operator with them.

string a = "one two three";


string b = "one";
string c = a - b;
cout << c << endl;
Division

Division
Division in C++ is done with the / operator.

double a = 25.0;
double b = 4.0;
printf("%f \n", a / b);

challenge

What happens if you:


Assign b to 0.0?
Assign b to 0.5?
Change the code to…

double a = 25.0;
double b = 4.0;
a /= b;
printf("%f \n", a);

Hint(s)
/= works similarly to += and -=.

important

IMPORTANT
Division by zero is undefined in mathematics. In C++, dividing by an
integer of 0 results in an error message. However, dividing by a
double of 0.0 results in inf which is short for infinity.

Integer Division
Normally, you use double in C++ division since the result usually involves
decimals. If you use integers, the division operator returns an int. This
“integer division” does not round up, nor round down. It removes the
decimal value from the answer.

.guides/img/IntDivision

int a = 5;
int b = 2;
cout << a / b << endl;
Modulo

Modulo
Modulo is the mathematical operation that performs division but returns
the remainder. The modulo operator is %.

.guides/img/Modulo

int modulo = 5 % 2;
cout << modulo << endl;

challenge

What happens if you:


Assign modulo to 5 % -2?
Assign modulo to 5 % 0?
Assign modulo to 5 % 2.0?
Multiplication

Multiplication
C++ uses the * operator for multiplication.

int a = 5;
int b = 10;
cout << a * b << endl;

challenge

What happens if you:


Assign b to 0.1?
Assign b to -3?
Change the code to…

int a = 5;
int b = 10;
a*=b;
cout << a << endl;

Hint(s)
*= works similarly to +=, -=, and /=.
Order of Operations

Order of Operations
C++ uses the PEMDAS method for determining order of operations.

.guides/img/PEMDAS

By default, there are no operators for exponents and square roots.


Instead, functions such pow( , ) and sqrt() are used to calculate powers
and square roots respectively. In order to use these functions, they must be
imported by including #include <cmath> at top of the program header. For
exponents, the base number goes before the , in pow( , ) and the exponent
goes after the ,. For example, pow(4, 2) calculates and pow(4, 0.5)
calculates or . For square roots, the number goes inside the () in
sqrt(). An example is sqrt(4) which calculates .

cout << pow(2, 2) << endl;


cout << pow(25, (1 / 2)) << endl;
cout << pow(25, (1.0 / 2.0)) << endl;
cout << sqrt(25) << endl;

pow(25, (1 / 2)) vs. pow(25, (1.0 / 2.0))


pow(25, (1 / 2)) results in 1 because integer division is performed within
(1 / 2). 1 divided by 2 returns in an integer of 0 and computes to 1. On
the other hand, pow(25, (1.0 / 2.0)) involves double division which is
why 5 was computed.

The code below should output 10.000000.

int a = 2;
int b = 3;
int c = 4;
double result = 3 * a - 2 / (b + 5) + c;
printf("%f \n", result);
Explanation

The first step is to compute b + 5 (which is 8) because it is surrounded


by parentheses.
Next, do the multiplication and division going from left to right: 3 * a is
6.
2 divided by 8 is 0 (remember, the / operator returns an int when you
use two ints so 0.25 becomes 0).
Next, perform addition and subtraction from left to right: 6 - 0 is 6.
Finally, add 6 and 4 together to get 10.
Since result is of type double, 10.000000 is printed.

challenge

Mental Math
5 + 7 - 10 * 4 / 2
Solution
-8
5 * 8 - 7 % 2 - 18 * -1
Solution
57
9 / 3 + (100 % 100) - 3
Solution
0
12 - 2 * pow(2, 3) / (4 + 4)
Solution
10
Type Casting

Type Casting
Type casting (or type conversion) is when you change the data type of a
variable.

int numerator = 40;


int denominator = 25;
int number = 0;
cout << boolalpha << (bool) number << endl;
cout << numerator / denominator << endl;
cout << (double) numerator / denominator << endl;

numerator and denominator are integers, but (double) converts numerator


into a double. You can use (double), (int), and (bool) to cast any double,
integer, or boolean between each other. Note that casting an integer of 0 or
a double of 0.0 to a boolean will result in false. Any other integer or
double values will result in true.
challenge

What happens if you:


Assign number to 5?
Cast only denominator to a double?
Cast both numerator and denominator to a double?
Cast the result to a double (e.g. (double) (numerator /
denominator)?
Change the code to…

int numerator = 40;


int denominator = 25;
int number = 5;
cout << boolalpha << (bool) number << endl;
cout << numerator / denominator << endl;
cout << (double) numerator / denominator << endl;
printf("%d \n", numerator / denominator);
printf("%f \n", (double) numerator / denominator);
printf("%f \n", (double) (numerator / denominator));

More information
If either or both numbers in C++ division are doubles, then double division
will occur. In the last example, numerator and denominator are both ints
when the division takes place which results in an int of 1. An integer of 1
converted to a double is 1.000000 but cout removes the decimal point and
all of the trailing zeros.

Data Type Compatibility


Do you know why the code below will not work?

int a = 5;
string b = "3";
cout << a + b << endl;

In C++, you can add a combination of ints, doubles, and bools together.
Remember that a boolean is either 1 if it’s true or 0 if it’s false. In the
example above, adding a string to an integer results in an error. That’s
because a string has no numerical value and can only be added to other
strings. However, you can convert the string b to an integer to fix the
problem by using stoi(). stoi() acts as a function to convert a string into
an integer. The string or string variable goes into the () to be converted.
See below for a list of type-conversion functions.

int a = 5;
string b = "3";
string c = "3.14";
bool d = true;
cout << a + stoi(b) << endl;

List of commonly used type-conversion functions

Output
Function Input Type Example
Type
stoi() string int stoi(“10”)

stod() string double stod(“12.34”)

int, double, to_string(10), to_string(12.34),


to_string() string
or boolean or to_string(false)

challenge

What happens if you:


Replace stoi(b) with stoi(c)?
Replace stoi(b) with stod(c)?
Replace stoi(b) with to_string(d)?
Replace a + stoi(b) with b + to_string(d)?

important

IMPORTANT
You can convert the string "3.14" to an integer using stoi() which will
result in an int of 3. To retain the decimal places, use stod() instead. In
addition, the to_string() function will convert a boolean into the
string form of its numerical value. to_string(true) will convert true to
"1" instead of 1. This is why adding b, which is a string of "3", to
to_string(d) resulted in the string of "31".
Learning Objectives: Boolean
Operators

Recognize the difference between = and ==

Understand the && and || operators’ functions

Evaluate boolean expressions


Equal To & Not Equal To

Boolean operators are operators that return a boolean value (true or


false).

Equal To
C++ uses the == operator to determine equality. Beginners often confuse the
= and the == operators. Remember, = is the assignment operator.

int a = 5;
int b = 5;
cout << boolalpha << (a == b) << endl;

challenge

What happens if you:


Assign b to 1?
Change a to bool a = true; and b to bool b = false;?

Not Equal To
The != operator checks to see if two values are not equal.

int a = 5;
int b = 5;
cout << boolalpha << (a != b) << endl;
challenge

What happens if you:


Assign b to 1?
Change a to bool a = true; and assign b to 1?
Change b to bool b = false;?
Less Than & Less Than or Equal To

Less Than
The < operator is used to check if one value is less than another value.

int a = 5;
int b = 7;
cout << boolalpha << (a < b) << endl;

challenge

What happens if you:


Assign b to 1?
Assign b to 5?
Assign b to false?

Hint(s)
It is possible to declare and assign int b = false; because false is just a
value of 0. Since 5 is not less than 0, false is returned.

Less Than or Equal To


The <= operator is used to check if one value is less than or equal to another
value.

int a = 5;
int b = 7;
cout << boolalpha << (a <= b) << endl;
challenge

What happens if you:


Assign b to 1?
Assign b to 5?
Assign a to false and assign b to true?

Hint(s)
false is less than true because 0 is less than 1.
Greater Than & Greater Than or
Equal To

Greater Than
The > operator is used to check if one value is greater than another value.

int a = 9;
int b = 17;
cout << boolalpha << (a > b) << endl;

challenge

What happens if you:


Assign b to 1?
Assign b to 9?
Assign b to false?
Assign b to true?

Hint(s)
9 is both greater than the value of false, which is 0, and the value of true,
which is 1.

Greater Than or Equal To


The >= operator is used to check if one value is greater than or equal to
another value.

int a = 9;
int b = 17;
cout << boolalpha << (a >= b) << endl;
challenge

What happens if you:


Assign b to 1?
Assign b to 9?
Assign a to true and assign b to false?

Hint(s)
true is greater than false.
And

The && Operator


The && (and) operator allows for compound (more than one) boolean
expressions. All boolean expressions must be true in order for the whole
thing to be true. If at least one boolean expressions is false, then the whole
thing is false.

bool a = true;
bool b = true;
bool c = false;
cout << boolalpha << (a && b) << endl;

How do I type &&?


It is located towards the top of the keyboard, on the same key as the
number 7. Hold shift and press the 7 key to type &.

challenge

What happens if you:


Replace (a && b) in the code above with (a && c)?
Replace (a && b) in the code above with (b && c)?

Multiple && Statements


You can chain several && expressions together. They are evaluated in a left-
to-right manner.

bool a = true;
bool b = true;
bool c = false;
cout << boolalpha << (a && b && c) << endl;
challenge

What happens if you:


Replace (a && b && c) in the code above with (a && b && a && b
&& a)?
Replace (a && b && c) in the code above with (a && b && a && b
&& c)?

Hint(s)
c is the only variable is that is false. Thus, if c is involved in an &&
expression, the entire thing will evaluate to false. Any combinations of as
and/or bs will result in true.
Or

The || Operator
The || (or) operator allows for compound (more than one) boolean
expressions. If at least one boolean expression is true, then the whole thing
is true. To be false, all boolean expressions must be false.

bool a = true;
bool b = true;
bool c = false;
bool d = false;
cout << boolalpha << (a || b) << endl;

How do I type ||?


It is towards the right-hand side, below the backspace or delete key and
above the enter or return key. The | symbol is located on the same key as
the </code> symbol. Hold shift and press the </code> key to type |.

challenge

What happens if you:

Replace (a || b) in the code above with (a || c)?

Replace (a || b) in the code above with (c || d)?

Multiple || Statements

You can chain several || expressions together. They are evaluated in a left-to-
right manner.
bool a = true;
bool b = true;
bool c = false;
cout << boolalpha << (a || b || c) << endl;

challenge

What happens if you:

Replace (a || b || c) in the code above with (a || c || c || c || c)?

Replace (a || b || c) in the code above with (c && c && c && c && c)?
Not

The ! Operator
The ! (not) operator produces the opposite result of the boolean expression
that it modifies.

cout << boolalpha << (! true) << endl;

challenge

What happens if you:


Replace (! true) in the code above with (! true && false)?
Replace (! true) in the code above with (! (true && false))?
Replace (! true) in the code above with (! ! true)?

Hint(s)
The ! operator works similarly to how a - (negative) sign works in
mathematics. The - of a positive number is a negative number and the - of
a negative number is a positive number.

Order of Boolean Operators


Much like how arithmetic operators are evaluated in a certain order,
boolean operators also work according to their priority level. Boolean
operations are evaluated in the following order from highest to lowest
priority:

1. Parentheses ()
2. Not !
3. And &&
4. Or ||
Short Circuiting

Short Circuiting
If C++ can determine the result of a boolean expression before evaluating
the entire thing, it will stop and return the value.

.guides/img/ShortCircuiting

cout << boolalpha << (false


&&
/*C++ never reaches this line*/ true) << endl;

cout << boolalpha << (true


||
/*C++ never reaches this line*/ false) << endl;
Lab: Arithmetic Operators

Tutorial Lab 1: Arithmetic Operators


Arithmetic operations in C++ are mostly the same as what you learned in
math class. However, the symbols used in C++ may be different.

Operation Symbol Notes


Addition +
Subtraction -
Multiplication *
Division /
Returns the remainder after division is
Modulo %
performed.

Use the text editor on the left to enter the following code:

cout << 10 + 3 << endl;


cout << 10 - 3 << endl;
cout << 10 * 3 << endl;
cout << 10 / 3 << endl;
cout << 10 % 3 << endl;

Program results:
1) Addition works as expected.
2) Subtraction works as expected.
3) Multiplication works as expected.
4) Division with integers will return a truncated integer result.
5) Modulo returns 1 because that is the remainder (not the decimal) after
division is performed.
Lab: Strings

Tutorial Lab 2: Strings


You can use the + operator with strings, even though the result is not based
on math. Using the + operator with strings is called concatenation.

Use the text editor on the left to enter the following code:

string string1 = "hip ";


string string2 = string1 + string1;
string string3 = "hoo";
string string4 = "ray!";
string string5 = string3 + string4;
cout << string2;
cout << string5 << endl;

Below are the steps that C++ takes when evaluating the code above.
1) Assign the value "hip " to the variable string1. Note the inclusion of a
space after the word hip.
2) The variable string2 will have the value of "hip hip " because string1
+ string1 repeats the value of string1 two times.
3) Declare string3 and assign it the value of "hoo".
4) Declare string4 and assign it the value of "ray!".
5) Declare string5 and assign it the value of string3 combined with the
value of string4 ("hooray!").
6) Print the value of string2 ("hip hip ") without the newline character.
7) Print the value of string5 ("hooray!") to the end of string2.
Lab: Order of Operations

Tutorial Lab 3: Order of Operations


C++ uses PEMDAS when determining the order of operations.

.guides/img/PEMDAS

Modulo and PEMDAS


Since modulo is based on division, modulo operations happen at the time
of multiplication and division, going from left to right.

Use the text editor on the left to enter the following code:

cout << (5 * 8 / 3 + (18 - 8) % 2 - 25) << endl;

Below are the steps that C++ takes when evaluating the code above.
1) 5 * 8 / 3 + (18 - 8) % 2 - 25
1) 5 * 8 / 3 + 10 % 2 - 25
1) 40 / 3 + 10 % 2 - 25
1) 13 + 10 % 2 - 25
1) 13 + 0 - 25
1) 13 - 25
1) -12
Lab: Boolean Operators

Tutorial Lab 4: Boolean Operators


Boolean operators are used within expressions to return either true or
false.

Operation Symbol Notes


The = operator is
the assignment
Equal to == operator, not the
equality
operator.
Not equal to !=

Less than <

Less than or equal to <=

Greater than >

Greater than or equal to >=

Compares two
boolean
expressions.
Both must be
And &&
true for the
whole to be
true. Everything
else is false.
Compares two
boolean
expressions.
Both must be
Or ||
false for the
whole to be
false. Everything
else is true.
Returns the
opposite result
Not ! of an evaluated
boolean
expression.
The following code is available within the text editor on the left. Click the
TRY IT button below to see the printed result.

cout << boolalpha << ((5 > 7) && (false || 1 < 9) || 4 != 5 && !
(2 >= 3)) << endl;

Below are the steps that C++ takes when evaluating the code above.

Evaluate all arithmetic operators according to PEMDAS

1. (5 > 7) && (false || 1 < 9) || 4 != 5 && ! (2 >= 3)


2. false && (false || 1 < 9) || 4 != 5 && ! (2 >= 3)
3. false && (false || true) || 4 != 5 && ! (2 >= 3)
4. false && (false || true) || true && ! (2 >= 3)
5. false && (false || true) || true && ! false

Evaluate all boolean operators according to this order -


Parentheses (()), Not (!), And (&&), then Or (||)

6. false && true || true && ! false


7. false && true || true && true
8. false || true && true
9. false || true
10. true

==Note== that arithmetic operators are performed before boolean


operators.
Lab Challenge: Operators

Operators Challenge
Write a boolean expression that incorporates ONE of the equality
operators, ONE of the less than operators, ONE of the greater than
operators, and TWO of the logical operators. The result of your overall
boolean expression MUST be false. Make sure to use cout << boolalpha <<
in your code. Otherwise, the system will print 0 or 1 instead of false or
true.

Equality Less Than Greater Than Logical


== < > &&

!= <= >= ||

!
Learning Objectives: If Else
Statement

Describe if-else statement syntax

Explain the difference between an if statement and an


if-else statement
If Else Statement Syntax

If Else Syntax
The if-else statement checks to see if a condition is true, and then has
specific actions that take place. However, it also provides a specific set of
actions if the boolean expression is false. Use the else keyword to
introduce the code to run when false is evaluated. Note that else is aligned
with the if keyword (no indentation) and has its own set of curly braces {}.
You do not write another boolean expression with else.

.guides/img/IfElseSyntax

It is best practice to indent the lines of code within the curly braces to
differentiate them but the indention does not affect how the program runs.

if (5 > 4) {
cout << "Print me if true" << endl;
}
else {
cout << "Print me if false" << endl;
}

Code Visualizer
challenge

What happens if you:


Change 4 in the code above to 6?
Remove all the curly braces {}?
Add cout << "False" << endl; under cout << "Print me if
false" << endl; without any curly braces {} in the code?
Add cout << "True" << endl; under cout << "Print me if true"
<< endl; without any curly braces {} in the code?

Code Visualizer

important

IMPORTANT
You may have noticed that when there is only one command
associated with an if or else statement the curly braces {} become
optional.

When Are Curly Braces Mandatory?


Curly braces {} are mandatory whenever you have more than one
command that is associated with an if or else statement. Here is a code
snippet that will work without curly braces:

if (10 % 2 == 0)
cout << "10 is even" << endl;
else
cout << "10 is odd" << endl;

However, if you add more commands to the if or else statement, the


program will not run properly. The examples below will not print as
intended or will produce an error message.
if (10 % 2 == 0) if (10 % 2 == 0)
cout << "10 is even" << endl; cout << "10 is even"
else cout << "True" << endl
cout << "10 is odd" << endl; else
cout << "False" << endl; cout << "10 is odd" <<

Like indentations, it is best practice to always include curly braces even if


they are optional in certain situations.

if (10 % 2 == 0) { // mandatory curly braces


cout << "10 is even" << endl;
cout << "True" << endl;
}
else { // optional curly braces
cout << "10 is odd" << endl;
}
If Else Statement

If Else Statement
The if-else statement is used when you want something specific to happen
if the boolean expression is true and something else to happen if it is false.

bool my_bool = true;

if (my_bool) {
cout << "The value of my_bool is true" << endl; }
else {
cout << "The value of my_bool is false" << endl; }

challenge

What happens if you:


Assign my_bool to false?
Assign my_bool to ! true && ! false?
important

IMPORTANT
Did you notice that the code above has the closing curly brace } after
the the semi-colon ; instead of on the next line? Remember that curly
braces {} are optional if the if-else statement only includes one
command within the if and else bodies. However, they are mandatory
when there is more than one command. When using curly braces, the
decision of where to place them is entirely up to you. All of the
commands below work exactly the same way:

if (is_true) {
cout << "1" << endl;
cout << "2" << endl;
}

if (is_true) {
cout << "1" << endl; cout << "2" << endl; }

if (is_true) { cout << "1" << endl; cout << "2" << endl; }

Testing Multiple Cases


You will find yourself needing to test the same variable multiple times. To
simplify this, you can nest if-else statements – which means you can put
an if-else structure inside of another if-else structure (as shown on the
right below).

.guides/img/NestedElseIf
When nesting if and else together, use the keywords else and if side-by-
side (else if). This nesting drastically changes the way the program flows
once the correct case is found. On the left, the program checks every case
no matter the value of the variable. On the right, the nested structure
causes the program to jump out of the structure once the correct case is
found. This is able to occur because the other if cases are inside the else
statement, which will only run when the previous boolean expression is
false.

int grade = 62;


if (grade < 60) {
cout << "F" << endl; }
else if (grade < 70) {
cout << "D" << endl; }
else if (grade < 80) {
cout << "C" << endl; }
else if (grade < 90) {
cout << "B" << endl; }
else if (grade <= 100) {
cout << "A" << endl; }

Code Visualizer
Learning Objectives: Switch Case
Statement

Describe the switch case syntax

Identify when to apply switch case statements instead of


nested if-else
Switch Case Statement Syntax

Swith Case Statement Syntax


The switch case statement is a way to make a decision with multiple
possible outcomes. Instead of nesting or sequencing many if statements,
C++ allows you to write the following:

.guides/img/SwitchCase

Here are the rules for writing a switch case statement:

Start with switch followed by the variable that is going to be tested in


parentheses ().
All of the cases are surrounded by a set of curly braces {}.
Each case is followed by a numerical value and a colon :.
After each :, write the code that should run if the variable is equal to
that case’s value.
After each section of code per case, include break;.
As the very last case, use default: to specify what should happen if
none of the above cases are true.
int dayOfWeek = 3;

switch (dayOfWeek) {

case 1: cout << "Sunday"; //only prints if dayOfWeek == 1


break;
case 2: cout << "Monday"; //only prints if dayOfWeek == 2
break;
case 3: cout << "Tuesday"; //only prints if dayOfWeek == 3
break;
case 4: cout << "Wednesday"; //only prints if dayOfWeek == 4
break;
case 5: cout << "Thursday"; //only prints if dayOfWeek == 5
break;
case 6: cout << "Friday"; //only prints if dayOfWeek == 6
break;
case 7: cout << "Saturday"; //only prints if dayOfWeek == 7
break;
default: cout << "Invalid"; //only prints if none of the above
are true

Code Visualizer

challenge

What happens if you:


Assign dayOfWeek to 5?
Assign dayOfWeek to 0?
Assign dayOfWeek to 3 and remove all of the break; statements?

Code Visualizer
Switch Case vs. If Else

Switch Case vs. Else If


C++ allows you to use either switch case or a series of else if statements
to handle decisions with multiple outcomes. There are a couple of reasons
why you would use one method over the other.

#1: Else If is used for ranges of values - Switch Case is for


specific values

switch case can only check for equality (e.g. num == 5), so if you need to
check for a range of values (e.g. num > 50 && num <= 60), use else If
instead.

.guides/img/SwitchCaseElseIf

What is case 10: case 9:?

Sometimes, the code for multiple cases is the same. Instead of repeating
code, you can list multiple cases before the code. Here is another
example:
int month = 2;
int year = 2000;
int numDays = 0;

switch (month) {
case 1: case 3: case 5:
case 7: case 8: case 10:
case 12:
numDays = 31;
break;
case 4: case 6:
case 9: case 11:
numDays = 30;
break;
case 2:
if (((year % 4 == 0) &&
! (year % 100 == 0)) ||
(year % 400 == 0))
numDays = 29;
else
numDays = 28;
break;
default:
cout << "Invalid month.";
break;
}
cout << "Number of Days = " << numDays << endl;

In some cases, as shown above, you can exploit patterns to force ranges
into a switch case, but frequently that is not possible and it also makes the
code less readable. For example, above, the user has to realize that
letterGrade is using integer division to retrieve the tens place of the
original grade.
int grade = 62;
int letterGrade = grade / 10;
switch (letterGrade) {
case 10: case 9: cout << "A";
break;
case 8: cout << "B";
break;
case 7: cout << "C";
break;
case 6: cout << "D";
break;
default: cout << "F";
}

Code Visualizer

#2: Else If is used for handling multiple variables

switch case can only compare against values - not variables. For example,
if you wanted to compare the inputted day of the week with the current
day of the week, you would need to use else if. switch case can handle
values (dayOfWeek == "Sunday") but not variables (dayOfWeek == today).

#3: Else If is used for compound conditionals

To check multiple conditions, an else if is needed.

Below is an example of a multiple choice grader using switch case:


int studentAnswer = 3;
string feedback1 = "This answer is wrong because....";
string feedback2 = "This answer is correct! You know this
because...";
string feedback3 = "This answer is wrong. While the first part
is correct...";
string feedback;

int correctAnswer = 2;
int points = 0;

switch (studentAnswer) {
case 1: feedback = feedback1; break;
case 2: feedback = feedback2; break;
case 3: feedback = feedback3; break;
default: feedback = "Invalid answer choice";
}

cout << feedback << endl;

challenge

Switch Case to Else If

Change the switch case statements above into else if statements.


Add a check to see if studentAnswer == correctAnswer.
If the student’s answer is correct, increment (++) the points
variable.
Print out the student’s earned points at the end of the program
using the points variable.

Code Visualizer

Sample solution
if (studentAnswer == 1) {
cout << feedback1 << endl;
}
else if (studentAnswer == 2) {
cout << feedback2 << endl;
}
else if (studentAnswer == 3) {
cout << feedback3 << endl;
}
else {
cout << feedback << endl;
}

if (studentAnswer == correctAnswer) {
points++;
}

cout << points << endl;


Lab: If Statement

Tutorial Lab 1: If Statements


The if statement allows for your program to make a decision about what it
should do. It asks a simple question: “Is this condition true?” If yes, then the
computer will execute certain commands.

int x = 5;

if (x < 10) {
cout << "Less than 10" << endl;
}

Code Visualizer

An if statement is comprised of the keyword if, followed by a boolean


expression surrounded by parentheses (). Any code that should run if the
boolean expression is true is surrounded by curly braces {}. It is best
practice to indent this code, but it does not affect how the code runs.

If the boolean expression is false, the code in curly braces is skipped, and
the program continues as normal.

int x = 20;

if (x < 10) {
cout << "Less than 10" << endl;
}

cout << "And the program continues...";

Code Visualizer

if statements can be used to test multiple conditions. These conditions


exist as boolean expressions inside the parentheses (). In addition, an if
statement can exist inside another if statement. Both blocks of code below
accomplish the same exact task.
int age = 15; int age = 15;

if (age < 20) { if ((age < 20) && (age > 10)) {
if (age > 10) { cout << "Teenager";
cout << "Teenager"; }
}

Code Visualizer
Lab: If Else Statement

Tutorial Lab 2: If Else Statements


The if else statement gives your program the ability to ask a question,
perform certain actions if the answer is true, and then perform another set
of actions if the answer is false.

int x = 10;

if (x > 50) {
cout << to_string(x) + " is greater than 50" << endl;
}
else {
cout << to_string(x) + " is less than 50" << endl;
}

Code Visualizer

The if part of the if else statement is written as before. The else keyword
is not indented; it should be aligned with the if keyword. else is followed
by an open curly brace {. You do not use a boolean expression with else.
All code that should run when the boolean expression is false should go
before the closing curly brace }.

Be careful when expressing your boolean expression in terms of “less than


or greater than”. This does not take into account when the values being
compared are equal. Consider the code from above, but with x having the
value of 50.

int x = 50;

if (x > 50) {
cout << to_string(x) + " is greater than 50" << endl;
}
else {
cout << to_string(x) + " is less than 50" << endl;
}

Code Visualizer
The output of the program does not make sense. 50 is not less than 50.
Sometimes using <= and >= need to be used. Another solution is to update
the output to be more inclusive such as replacing is less than 50 with is
less than or equal to 50. In either case, be sure to think through all of
the possible outcomes, and make sure your code can function properly in
all of those scenarios.
Lab: Switch Statement

Tutorial Lab 3: Switch Statement


The switch case statement gives your program the ability to perform
different actions based on the value of a given variable.

int size = 3;

switch (size) {
case 1: cout << "Short"; break;
case 2: cout << "Tall"; break;
case 3: cout << "Grande"; break;
case 4: cout << "Venti"; break;
case 5: cout << "Trenta"; break;
default: cout << "Grande";
}

Code Visualizer

The variable used to make the decision is in parentheses following the


switch keyword. Inside curly braces, the cases listing the different values to
check are followed by a : and then the code that should run if the variable
is equal to that case’s value comes next. The last case, default, runs if none
of the other cases are true. Each code segment except the last one ends with
break; to signal the program to jump to the closing curly brace.

Remember to include break; statements at the end of each case. Check out
what happens when you remove them.

int size = 3;

switch (size) {
case 1: cout << "Short";
case 2: cout << "Tall";
case 3: cout << "Grande";
case 4: cout << "Venti";
case 5: cout << "Trenta";
default: cout << "Grande";
}

Code Visualizer
The output of the program does not make sense because the program
continues through all of the cases after the initial case is matched to a
value. In the example above, the program prints the command for case 3
as well as all of the commands that follow.
Lab Challenge: Month of the Year

Conditionals Challenge
Write a program that determines the month of the year based on the value
of a variable called month. The variable will be a number from 1 to 12 (1 is
January, 2 is February, etc.). Use a cout << statement to write the month to
the screen.

Click to compile your code

Test your code with a few different values


Learning Objectives: For Loops

Explain for loop syntax

Identify the causes of an infinite loop

Identify the relationship between patterns, loops, and


output
For Loops

For Loop Syntax


Before you can start writing a loop, you need to be able to identify
recurring patterns. Let’s take something simple:

cout << "Hello" << endl;


cout << "Hello" << endl;
cout << "Hello" << endl;
cout << "Hello" << endl;
cout << "Hello" << endl;

The pattern is cout << "Hello" << endl;, and it is repeated five times.
Since we know that the loop needs to run exactly five times, a for loop can
be used. Here is how you write a for loop that repeats five times. Copy the
code below into the text editor on the left and then click on the TRY IT
button to see the output. You can also click on the ++Code Visualizer++ link
below to see how a for loop works behind the scenes. If the visualizer does
not boot up correctly, click on the Refresh code button to restart it. Use the
Forward > and Back < buttons to navigate the program.

for (int i = 0; i < 5; i++) {


cout << "Hello" << endl;
}

Code Visualizer

Like conditionals, for loops are code blocks. However, in addition to a


boolean statement(s), you also declare, initialize, and increment a variable
called the loop iterator. All of the code that will be repeated are placed
between the curly braces {}. It is recommended that you indent the code
within the curly braces, but it is not necessary for the loop to run.

Understanding the Loop Header


Copy the code below and TRY IT.
for (int i = 0; i < 5; i++) {
cout << "Loop #" << i << endl;
}

Code Visualizer

The loop ran five times, but the variable i did not start at 1. Instead, it
started at 0. C++ , like most programming languages, starts counting from 0
by default. C++ will continue counting up to, but not including, 5. The i++
tells the system to continue counting up by 1 and the i < 5 tells the system
to stop counting before reaching 5.

challenge

What happens if you:


Replace "Loop #" << i in the code above to "Loop #" << i + 1?
Replace i < 5 with i < 6 in the loop header and change the print
statement back to "Loop #" << i?
Replace i < 5 with i <= 5 in the loop header?
Replace i++ with i-- in the loop header?

Code Visualizer

Infinite Loops
If you aren’t careful, you can wind up with an infinite loop. This means
that you have a loop that never ends. In the example above, if you change
i++ to i– then i will decrease by 1 after every iteration. This causes the loop
iterator to never reach its specified value. The boolean expression
continues to be true and the system continues to print until it times out.
Always check your loop header to ensure that it does what you intend for it
to do.
Turtle Graphics

Before continuing with loops, we are going to learn how to create graphical
output with the Turtle Graphics library. Like a pencil on paper, the turtle
object leaves a line as it moves around the screen.

Turtle Syntax
The first step is to create a screen for the turtle to move around in using
the command TurtleScreen followed by a variable name to call that screen
(i.e. screen). In parentheses after screen, you can specify the dimensions of
the screen in terms of width and height respectively (i.e. 400, 300). Then
we can create our turtle using the command Turtle followed by a variable
name for that turtle (i.e. tina). Finally in parentheses, we put in screen to
associate the turtle with the screen that we created previously. The code
below produces a turtle and a screen for the turtle to move around in.

TurtleScreen screen(400, 300); //width 400 pixels and height 300


pixels
Turtle tina(screen); //creates a turtle named tina inside the
screen

important

IMPORTANT

You may have noticed that there are additional lines of code within the
file in the text editor to your left. It is very IMPORTANT that you DO
NOT edit the header as that will cause the program to run incorrectly.

#include <iostream>
#include "CTurtle.hpp"
#include "CImg.h"
using namespace cturtle;
using namespace std;

The header above enables you to use the Turtle Graphics library as
well as the C Image library. Thus, the header should never be altered.
Turtle Commands
In order to view the turtle object, it is not enough just to create it. You must
give instructions to the turtle object in order for it to “move” around the
screen. Here is a list of basic turtle commands that you can give to tina the
turtle object:

Command Parameter Description


Where n represents
tina.forward(n) Move the turtle forward
the number of pixels
Where n represents
tina.backward(n) Move the turtle backward
the number of pixels
Where d represents
tina.right(d) Turn the turtle to the right
the number of degrees
Where d represents
tina.left(d) Turn the turtle to the left
the number of degrees

Let’s try this very simple command below. Copy it into the text editor on
your left and then click the TRY IT button to see the graphical output.

TurtleScreen screen(400, 300);


Turtle tina(screen);
tina.forward(100);
screen.exitonclick();

What does the screen.exitonclick() command do?

By default, the screen will close itself automatically once the program
reaches the end of the code. However, if you want the screen to remain
open, you can use screen.exitonclick() to tell the program to keep the
screen open until the screen is clicked with a cursor. Go ahead and try
clicking on the screen.

Turtle Output
Below is an image highlighting what happens after the TRY IT button is
clicked.
.guides/img/TurtleGraphicsFlow

1. TRY IT button is clicked by the user.


2. The Terminal tab is opened.
3. The terminal runs the command to compile the program and to display
the graphical output.
4. The output is displayed as a screen on the bottom left panel. You can
click the screen to close the output.
5. Click on the turtleloop.cpp tab to go back to the text editor if you want
to make changes to the program.
Turtle Coding: For Loop

Customize Your Turtle


You may choose to change the dimensions of your turtle screen whenever
you’d like. Also, the following table provides additional commands you can
use to customize tina the turtle.

Command Parameter Examples


Where COLOR
represents the
red, orange, yellow,
tina.pencolor({"COLOR"}) track or line color
green, blue, purple
you want tina to
leave behind
Where W
represents how any positive integer
tina.width(W)
wide (in pixels) (e.g. 1, 10, 123, etc.)
tina’s track is
Where SHAPE
triangle, indented
tina.shape("SHAPE") represents the
triangle, square, arrow
shape tina takes
TS_FASTEST, TS_FAST,
Where SPEED
TS_NORMAL,
tina.speed(SPEED) represents how
TS_SLOW,
fast tina moves
TS_SLOWEST

Turtle Challenges
Now that you know how to customize tina, try to recreate the images you
see below using your knowledge of for loops.

Challenge 1
.guides/img/TurtleChallenge1

Hint
There are multiple ways to accomplish this task but the trick lies within
finding the pattern and then repeating it a specific number of times. One
pattern in particular is to:

1. Go forward (creating a long line).


2. Make a right turn.
3. Go forward (creating a small line).
4. Make a right turn.
5. Go forward (creating another small line).
6. Make a right turn.
7. Go forward (creating a final small line).
8. Repeat steps #1 through #7 three more times for a total of four
iterations.

The pattern should look something like this:

Challenge 2

.guides/img/TurtleChallenge2

Hint
Since a circle has 360 degrees, you will need a loop that repeats 360 times.
Be careful about how far the turtle moves forward and turns. The circle
can get very big, very quickly.
Challenge 3

.guides/img/TurtleChallenge3

Hint
The pattern here is to move forward and make a right turn.

The trick lies within the fact that the distance the turtle moves has to get
larger as the loop advances. Think of some operators that you can use to
make the loop iterator variable get bigger during each iteration.

info

NOTE

Due to the dynamic and graphical nature of the Turtle Graphics library,
jagged lines and spotty pixels may appear randomly as the output is
being drawn. This is completely normal!

.guides/img/CppJaggedLine

Still having trouble with creating the outputs above?


Here are some sample solutions:

tina.pencolor({"blue"});
tina.width(2);
tina.shape("arrow");
tina.speed(TS_SLOWEST);

for (int i = 0; i < 4; i++) {


tina.forward(75);
tina.right(90);
tina.forward(25);
tina.right(90);
tina.forward(25);
tina.right(90);
tina.forward(25);
}

tina.pencolor({"red"});
tina.width(2);
tina.shape("square");
tina.speed(TS_FASTEST);

for (int i = 0; i < 360; i++) {


tina.forward(1);
tina.right(1);
}

tina.pencolor({"green"});
tina.width(2);
tina.shape("triangle");
tina.speed(TS_NORMAL);

for (int i = 10; i <= 200; i+=10) {


tina.forward(i);
tina.right(90);
}
Learning Objectives: While Loops

Explain while loop syntax

Identify the causes of an infinite while loop

Describe the break statement as it relates to a while loop


While Loops

While Loop Syntax


while loops, like for loops, use curly braces {} and indents for all
commands that should be repeated. However, for loops generally contain 3
elements (an initialized variable, a boolean expression involving that
variable, and a change in the value of that variable) while a while loop
usually contains just a boolean expression. The for and while loops below
produce the same results.

for (int i = 0; i < 5; i++) { int i = 0;


cout << "Loop#: " << i << while (i < 5) {
endl;
cout << "Loop# " << i << endl
}
i++;
}

Note that the variable declaration and initialization happen before the start
of the while loop and any changes that occur to the variable happen within
the body of the curly braces {}. On the other hand, everything happens in
one step within parentheses () when using a for loop.

Here is another example of a while loop that prints Hello based on the
value of the variable count.

int count = 5; // some random number set by user


while (count > 0) {
cout << "Hello" << endl;
count--;
}

Code Visualizer
challenge

What happens if you:


Change the while statement to while (count > -1 * count)?
Replace count-- in the code above with count = count - 2?
Change the while statement to while (count < 10)?

How does while (count > -1 * count) work?


To understand how the loop works, it’s best to substitute values in for the
variable count. In the first iteration, we have while (5 > -1 * 5), this
statement is true so the print command is executed. Since count gets
decremented by 1 with each iteration, the while loop condition changes
slightly every time like as follow:

while (4 > -1 * 4)
while (3 > -1 * 3)
while (2 > -1 * 2)
while (1 > -1 * 1)

Once the condition gets to while (0 > -1 * 0), it no longer holds true and
the while loop ends. The result is 5 Hellos being printed to the screen.

Infinite Loops
Infinite loops are loops that do not have a test condition that causes them to
stop. The following is a common mistake that results in an infinite loop:

int count = 5; // some random number set by user


while (count > 0) {
cout << "Hello" << endl;
}

Since the variable count never gets decremented. It remains at 5, and 5 will
forever be greater than 0, so the loop will never stop.

warning

Copy the code above and TRY IT to see what happens. C++ will
eventually stop the loop due to an output limit, but it may take some
time before this happens.

Why Use a While Loop?


If a while loop does the same thing as a for loop, then what is the purpose
of having both? while loops are actually more useful when you are waiting
for a certain event to occur. Imagine you are making a video game. The
game should continue until the player loses all of their lives. You don’t
know how long this will take, so a while loop is more appropriate. On the
other hand, if you have more specific loop parameters, a for loop will be
better.

int player_lives = 3;

while (player_lives > 0) {


// video game code
// goes here
}
Turtle Coding: While Loop

Instead of a for loop, recreate the images below using a while loop.

Turtle Graphics Review

tina.forward(n) - Where n represents the number of pixels.


tina.backward(n) - Where n represents the number of pixels.
tina.right(d) - Where d represents the number of degrees.
tina.left(d) - Where d represents the number of degrees.
tina.pencolor({“COLOR”}) - Where COLOR represents the track or line
color you want tina to leave behind.
tina.width(W) - Where W represents how wide (in pixels) tina’s track is.
tina.shape(“SHAPE”) - Where SHAPE represents the shape tina takes.
tina.speed(SPEED) - Where SPEED represents how fast tina moves

Challenge 1

.guides/img/TurtleChallenge1

Hint
The pattern is still the same:

1. Go forward (creating a long line).


2. Make a right turn.
3. Go forward (creating a small line).
4. Make a right turn.
5. Go forward (creating another small line).
6. Make a right turn.
7. Go forward (creating a final small line).
8. Repeat steps #1 through #7 three more times for a total of four
iterations.

However, a while loop usually contains only a boolean expression(s) in its


header. Thus, you must initialize a counting variable before the start of the
while loop. Also, that counting variable should be incremented inside the
body of the loop. The pattern you are trying to iterate is still the same:

Challenge 2

.guides/img/TurtleChallenge2

Hint
Since a circle has 360 degrees, you will need a loop that repeats 360 times.
Be careful about how far the turtle moves forward and turns. The circle
can get very big, very quickly.

Challenge 3

.guides/img/TurtleChallenge3

Hint
The pattern here is to move forward and make a right turn.

The trick lies within the fact that the distance the turtle moves has to get
larger as the loop advances. Think of some operators that you can use to
make the loop iterator variable get bigger during each iteration.

Sample Solutions
Here are some sample solutions using while loops:

tina.pencolor({"blue"});
tina.width(2);
tina.shape("arrow");
tina.speed(TS_SLOWEST);

int i = 0;
while (i < 4) {
tina.forward(75);
tina.right(90);
tina.forward(25);
tina.right(90);
tina.forward(25);
tina.right(90);
tina.forward(25);
i++;
}

tina.pencolor({"red"});
tina.width(2);
tina.shape("square");
tina.speed(TS_FASTEST);

int i = 0;
while (i < 360) {
tina.forward(1);
tina.right(1);
i++;
}

tina.pencolor({"green"});
tina.width(2);
tina.shape("triangle");
tina.speed(TS_NORMAL);

int i = 10;
while (i <= 200) {
tina.forward(i);
tina.right(90);
i+=10;
}
info

NOTE

In most cases, for loops and while loops can be used interchangeably.
It is up to you to decide which one is better suited for your task.
Break Statement

Infinite Loops Are Bad, Right?


Well, that depends. If an infinite loop is caused because the counting
variable isn’t incremented, then it’s a bug. However, some programmers
purposely create a condition that will always evaluate to true. Therefore,
the loop will always run. In such cases, a break statement is used to stop the
loop at a particular point in the program.

Take a look at the following program (also shown in the text editor on the
left).

#include <iostream>
using namespace std;

int main() {

srand(time(NULL)); // start randomizer every time program runs


while (true) {
cout << "This is an infinite loop" << endl;
int randNum = rand() % 100 + 1; // generate random number
between 1 and 100

if (randNum > 75) {


cout << "The loop ends" << endl;
break; // stop the loop
} // end if condition
} // end while loop

cout << "The program ends" << endl;

return 0;

Then click on the TRY IT button below a few times to run the code and see
the resulting outputs. You can also click on the ++Code Visualizer++ link
below to see how the code runs behind-the-scenes.

Code Visualizer
Even though while (true) will always evaluate as a true statement, the
loop never becomes infinite because of the break statement.

challenge

What happens if you:


Remove break; from the program?
Add break; to the line before cout << "The loop ends" << endl;?

Code Visualizer

Comparing While Loops

The while loops introduced on the previous pages look different from the
while loop covered on this page; however, they both have the same
components and behave similarly.

.guides/img/WhileLoopComparison
Learning Objectives: Nested Loops

Explain nested loop syntax

Identify the relationship between the variables in each


loop with the output produced
Nested Loops

A nested loop is a loop that exists inside of another loop. An advantage of


using nested loops is that the loops can work together to create unique and
complex outputs. However, due to their complexity potential, it is rare to
see the implementation of more than two nested loops. If possible, it is
recommended that you re-factor your code to reduce this complexity.

Syntax

The code below will draw a rectangle of 100 # in a 10 x 10 grid. The first
loop controls the row of output, while the second loop prints 10 # to the
screen.

for (int row = 0; row < 10; row++) { //outer loop


for (int col = 0; col < 10; col++) { //inner loop
cout << "#";
}
cout << "" << endl; //adds new line
}

Code Visualizer

challenge

What happens if you:


Replace row < 10 with row < 5 in the code above?
Replace col < 10 with col < 20 in the code above?

Code Visualizer

Nested Loop Coding Challenge 1

Using nested loops, write some code that outputs the following:
###########
###########
###########
###########
###########
###########
###########

Code Visualizer

Hint
The output is the same character (#). Make sure that your nested loops have
the right numbers in the boolean expressions to get the appropriate
number of rows and columns.

Nested Loop Coding Challenge 2

Using nested loops, write some code that outputs the following:

<<<<<<<<<<
>>>>>>>>>>
<<<<<<<<<<
>>>>>>>>>>
<<<<<<<<<<

Code Visualizer

Hint
The output is a < when the outer loop variable is even (0, 2, 4) and a > when
the outer loop variable is odd (1, 3).

Nested Loop Coding Challenge 3

Using nested loops, write some code that outputs the following:

1
22
333
4444
55555

Code Visualizer

Hint
Note how the pattern goes from 1 to 5 starting on line 1 (through line 5) and
prints the line number equal to the amount of times as that numbered line.
First, the outer loop should start at 1. Second, the inner loop should run the
same amount of times as the row number up to the row number’s limit.

Sample Solutions

There are multiple ways to solve the challenges above but here are some
sample solutions using various combinations of for and while loops:

int row = 0;
while (row < 7) {
int col = 0;
while (col < 11) {
cout << "#";
col++;
}
cout << "" << endl;
row++;
}

for (int row = 0; row < 5; row++) {


if (row % 2 == 0) {
int col = 0;
while (col < 10) {
cout << "<";
col++;
}
cout << "" << endl;
}
else {
int col = 0;
while (col < 10) {
cout << ">";
col++;
}
cout << "" << endl;
}
}
for (int row = 1; row <= 5; row++) {
for (int col = 1; col <= row; col++) {
cout << row;
}
cout << "" << endl;
}
Lab: For Loop

Tutorial Lab 1: Using the For Loop


Copy the code below into the text editor on the left. Then click on the TRY
IT button to see the resulting output and ++Code Visualizer++ link (below)
to see how the program runs line by line.

for (int x = 0; x < 11; x++) {


if (x % 2 == 0) {
cout << "Even" << endl;
}
else {
cout << "Odd" << endl;
}
}

Code Visualizer

Program Summary

1. The for loop runs through all the values of the variable x from 0 to 10
as specified in the loop header.
2. For each value of x, an expression is evaluated using a conditional if
statement.
3. If x modulo 2 evaluates to 0, then print Even followed by a newline
character.
4. If x modulo 2 does not evaluate to 0, then print Odd instead followed by a
newline character.
Lab: While Loop

Tutorial Lab 2: The While Loop


Copy the code below into the text editor on the left. Then click on the TRY
IT button to see the resulting output and ++Code Visualizer++ link (below)
to see how the program runs line by line.

int counter = 0;
while (counter < 10) {
cout << counter << endl;
counter = counter + 1;
}
cout << "while loop ended" << endl;

Code Visualizer

Program Summary

1. A counter variable is initialized to keep track of how many times the


loop will be executed.
2. The loop will run as long as counter is less than 10.
3. Each time the loop runs, the integer value of counter is printed to the
screen.
4. The value of counter is then incremented by 1.
5. When counter reaches 10, the boolean expression no longer evaluates
to true and the program will exit the loop.
6. Before the program terminates, a statement is printed to the screen,
indicating that the while loop has ended.
7. Recall that the while loop must have an exit condition. By incrementing
the counter variable, we ensure that the loop will eventually end. If we
do not increment counter in this loop, we will create an infinite loop
because counter will never reach 10 or greater.
Lab: Break Statement

Tutorial Lab 3: Breaking from the While Loop


Copy the code below into the text editor in the upper left panel. Then click
on the TRY IT button to run the resulting program in the Terminal in the
lower left panel.

What does cin >> input; do?


The cin >> input; command records what a user enters on the screen and
stores that information in the variable input. Note that input is of type
double.
What do cin.good() and cin.fail() do?
cin.good() checks to see if the input entered by the user was successful
while cin.fail() checks to see if the input failed. Since input is of type
double, only numerical values entered by the user will cause cin >> input
to be successful, anything else will cause the input to fail.

double result = 0;
double input;

while (true) {
cout << "Enter a number to add to sum. ";
cout << "Or enter a non-number to quit and calculate sum." <<
endl;
cin >> input;
if (cin.good()) {
result += input;
}
if (cin.fail()) {
cout << "Sum = " << result << endl;
break;
}
}

Program Summary

1. Declare the variable result and initialize it to 0. result will store the
total of the summation.
2. Declare the variable input. input will store the information that the
user enters.
3. Next we set up a while loop with true as the expression in the loop
header. We do this because we want the loop to continue running and
storing information from the user. Since we don’t know how much
information the user will enter, a while loop is best for the situation.
4. The user is prompted to enter some information and that information is
stored in the variable input which was declared earlier.
5. If the information was stored into input successfully, the value in input
will be added to the value in result, our total summation.
6. If the information was not stored into input successfully, then the
program will print out the total summation result and exit the while
loop.
Lab Challenge: Loop Patterns

Nested Loop Example


One of the benefits of nested loops is that they can be used to construct
complex patterns. Imagine a classroom full of students and they are
distributed evenly into smaller groups and asked to form a single line with
their groups. The outer loop is like the group leader (represent in red and
L) and the inner loop is like the rest of the group members (represented in
blue and M.

.guides/img/NestedLoopExample

for (int x = 0; x < 3; x++) {


cout << "L" << endl;
for (int y = 0; y < 3; y++) {
cout << "M" << endl;
}
}
What is the pattern described by the above example? There are 3 leaders
and each leader has 3 members. However, note that the example shows the
students standing in a vertical line. What if you want to arrange the
students in a horizontal line like this instead?

.guides/img/NestedLoopHorizontal

By removing the << endl commands from the code above, you can
accomplish this task. Alternatively, you can also make use of an if and else
statement instead of a nested loop. Both ways will produce the same result.

for (int x = 0; x < 3; x++) { for (int x = 0; x < 12; x++)


cout << "L"; if ((x == 0) || (x == 4) ||
for (int y = 0; y < 3; y++) {
{ cout << "L";
cout << "M"; }
} else {
} cout << "M";
}

Nested For Loop Challenge

challenge

Assignment:
For this challenge, you will use your knowledge of patterns,
conditionals, and nested for loops to produce the following output:
XOXOXOXOX
OXO
OXO
XOXOXOXOX
OXO
OXO
XOXOXOXOX
OXO
OXO

Requirement:
Your program must include at least two for loops, one nested within
another, in order to receive credit. In addition, you are only allowed to
use, at most, two cout statements.

Hint

You should start by determining a pattern that repeats itself. One


noticeable pattern is:

XOXOXOXOX
OXO
OXO

Try creating that particular pattern first, then iterate that pattern by
modifying the existing loop(s).
Learning Objectives: Array Basics

Create and initialize an array

Access and modify array elements

Iterate through arrays using both a regular for loop and


an enhanced for loop

Determine array output


Creating an Array

What Is an Array?
Before we discuss vectors, we will first learn about arrays, a simpler form
of a vector. An array is a data structure that stores a collection of data such
as ints, doubles, strings, etc. This data is often referred to as the array’s
elements. Being able to store elements into an array helps reduce the
amount of time needed to declare and initialize variables. For example, if
you wanted to store the ages of all family members in your household, you
would typically have to declare and initialize integer variables and values
for each family member. Copy the code below into the text editor on the
left and then click the TRY IT button to see the output. You can also click on
the ++Code Visualizer++ link underneath to see how the program runs
behind the scenes.

int Allan = 71;


int Bob = 42;
int Carol = 37;
int David = 5;
int Ellen = 18;

cout << Allan << endl;

Code Visualizer

challenge

What happens if you:


Change Allan in cout << Allan << endl to Bob, Carol, David, or
Ellen?

Code Visualizer

Array Creation
To avoid the repetitive task of declaring and initializing multiple variables,
you can declare an array and directly assign values or elements into that
array like below.

int ages[] = {71, 42, 37, 5, 18};

Code Visualizer

Method Syntax with Elements:

Specify the data type that the array will store (i.e. int).
Declare the variable name for the array (i.e. ages) followed by empty
brackets [] followed by the assignment symbol =.
Elements assigned to the array are separated by commas , and enclosed
within curly braces {}.

Additional information
If you used the Code Visualizer, you’ll notice that the array variable ages
refers to all of the elements as a collection. An array is considered to be a
collection that bundles all of the data that it holds.

Note that the first


array slot, or index, is always 0 so 71 is located at index 0 instead of 1.

Alternatively, you can create an array without any elements in which you
will need to declare and specify the array variable name and size before
you can assign elements to the array.

int ages[5];

Method Syntax without Elements

Specify the data type that the array will store (i.e. int).
Declare the variable name for the array (i.e. ages) followed by the
number of elements you want the array to hold within brackets (i.e.
[5]).
Additional information
Note that when you declare an array without initializing any elements, the
system will still reserve enough memory for the array to hold the specified
number of elements. This means that you can initialize elements within the
array later on.

Array Details
If an element within an array has not been initialized yet, printing it will
cause the system to output random memory data. Random memory data
is often generated when array elements are not initialized.

int ages[5];
cout << ages[0] << endl;

Note that ages[0] in the example above refers the element at index 0, also
known as the first position within the array. Currently, the element at the
first position is not initialized so printing the first element will only output
random memory data. In fact, the same will happen if you try to print any
other elements within the array. Additionally, all elements within the array
must be of the same type. If you try to store a string within an integer array,
or a double within a boolean array, you will get an error message.

int ages[] = {71, 42, 37, 5, "eighteen"};

cout << ages[4] << endl;

challenge

What happens if you:


Change "eighteen" in the code above to the integer 18?
Replace all your code with just int ages[];
important

IMPORTANT
When you create an array in C++, you must specify the number of
elements that you expect the array to hold. Otherwise, you will get an
error.

P.O. Boxes at the postal office are symbolically similar to arrays. Each row
of P.O. Boxes is like an array, except each box can only store one item
(element) and each item within that row must be of the same type
(i.e. integers).

.guides/img/ArrayElementsIndices
Accessing an Array

Array Access
To access and print array elements, you need to know their position. The
position at which an element is stored is called its index. For example,
names[0] refers to the first element in the array called names. Array indices
always start at 0 and increment by 1 with each element that comes next.
Due to this, numbers[4] refers to the fifth element in the array, not the
fourth.

string names[] = {"Alan", "Bob", "Carol", "David", "Ellen"};

cout << names[0] << endl;

challenge

What happens if you:


Change names[0] in the code above to names[2]?
Change names[0] in the code above to names[3]?
Change names[0] in the code above to names?

important

IMPORTANT
You may have noticed that printing the names array without specifying
an index resulted in an output that included a mixture of numbers and
letters. This occurs because printing an array actually prints its
memory location, not its elements. You’ll learn how to print all
elements in an array without having to specify all of their indices on a
later page.

Array Key Points


bool bools[] = {true, false, true};
double decimals[] = {2.3, 4};
int integers[1];

cout << bools[0] << endl;

challenge

What happens if you:


Change bools[0] in the original code to bools[1]?
Hint
The system will print 0 because bools[1] refers to the second
element in the bools array. Remember that 0 is the integer
equivalent to false and 1 is the integer equivalent to true. To print
their respective boolean equivalent, use cout << boolalpha <<
bools[1] << endl; instead.
Change bools[0] in the original code to decimals[1]?
Hint
The system will print 4 because decimals[1] refers to the second
element in the decimals array.
Change bools[0] in the original code to integers[1]?
Hint
The system will print random memory data because integers[1] is
not valid within the integers array. Currently there is only one
element at the first index which has not been formally initialized
yet.
Change int integers[1]; in the original code to int integers[1] =
{1.2}; and cout << bools[0] << endl; to cout << integers[0] <<
endl;?
Hint
The system will return an error message. Though you have tried to
initialize the first element within the integers array to 1.2, the
system will not allow you to put a double element into an integer
array. However, it is possible to put an integer element into a
double array because integers can be expressed as doubles but not
vice versa.
important

IMPORTANT
Here are some key points to keep in mind when working with arrays:

When you declare an array, you must specify the number of


elements you wish the array to hold before you can initialize any
elements. One exception is if you declare and initialize the array
and elements at the same time. Doing so means you do not need to
specify the number of elements in brackets [] since the system will
determine that based on the number of elements you have
initialized.

If you do not initialize any elements, printing the elements will only
result in random memory data.

If you try to access an element position that is not valid (i.e. the
second element in the integers array), the system will also output
random memory data.

Elements must be of the same type as the array. The only exception
is that integers can be expressed as doubles and can therefore be
put into a double array.

.guides/img/ArrayExceptions
Modifying an Array

Array Modification
To modify an element within an array, simply find the index at which that
element is stored and assign a new value to it.

int grades[] = {85, 95, 48, 100, 92};


cout << grades[2] << endl;

grades[2] = 88; //88 will replace 48 at index 2


cout << grades[2] << endl;

Code Visualizer

challenge

What happens if you:


Change int grades[] = {85, 95, 48, 100, 92}; in the code above
to int grades[5];?
Copy the original code but change all cout << grades[2] << endl;
to cout << grades[3] << endl;?
Change grades[2] = 88; in your current code to grades[3] = 100;?

Code Visualizer

Modifying Multiple Arrays


You can create and modify as many arrays as you’d like. For example, you
can create an array to store your family members and another array to
store their age.
string family[] = {"Dad", "Mom", "Brother", "Sister"};
int age[4];

cout << family[0] << " " << age[0] << endl;
cout << family[1] << " " << age[1] << endl;
cout << family[2] << " " << age[2] << endl;
cout << family[3] << " " << age[3] << endl;

Code Visualizer

challenge

What happens if you:


Add age[0] = 50; directly below the line int age[4];?
Add age[1] = 45; below the line int age[4]; but before the cout
statements?
Add age[2] = 25; below the line int age[4]; but before the cout
statements?
Add age[3] = 20; below the line int age[4]; but before the cout
statements?
Change "Sister" within the string array to "Brother2"?

Code Visualizer

important

IMPORTANT
Since the integer array above was created without any initialization,
random memory data were populated as elements within the array at
first. Then by setting the array indices to specific values, you were able
to modify the array to include the appropriate age for each family
member.
Iterating an Array

Array Iteration
Though we can add many elements to our array, printing each of them can
get quite tedious. For example, if we have 10 names of friends in our array,
we would need to specify each of their array index to print them.

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

cout << friends[0] << endl;


cout << friends[1] << endl;
cout << friends[2] << endl;
cout << friends[3] << endl;
cout << friends[4] << endl;
cout << friends[5] << endl;
cout << friends[6] << endl;
cout << friends[7] << endl;
cout << friends[8] << endl;
cout << friends[9] << endl;

Luckily, we can use loops which we had learned previously to help us with
this process. To print out all of our friends’ names without repeating the
print statement ten times, we can use a for loop to iterate 10 times.

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

for (int i = 0; i < 10; i++) {


cout << friends[i] << endl;
}
challenge

What happens if you:


Change cout << friends[i] << endl; in the code above to cout <<
friends[0] << endl;?
Change the cout statement to cout << friends[10] << endl;?

important

IMPORTANT
Did you notice that the print statement above includes i as the index
for friends? We do this because i will take on the values specified by
the for loop. The loop starts at 0 and increments by 1 until it reaches 9
(not including 10). Thus, friends[0] will print, then friends[1], so on
and so forth until friends[9] is printed. Then the loop ends.

Array Size
To make the iteration process easier, we can use the sizeof() operator to
determine how many elements are in our array. To use sizeof(), just call it
by using the keyword sizeof followed by the array name within
parentheses ().

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

cout << sizeof(friends) << endl;

Why Does sizeof(friends) output 320?

Unfortunately, the sizeof() operator does not determine the number of the
elements within an array. Instead, sizeof() calculates the size of the array
in bytes. In C++, a string takes up 32 bytes and since there are 10 string
elements in the array, the size of the array in bytes is 320.

To calculate the number of elements within an array, we will need to use


sizeof() twice.
string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",
"Fred", "Grace", "Henry", "Ian", "Jen"};

cout << sizeof(friends) / sizeof(friends[0]) << endl;

sizeof(friends) calculates the array’s size in bytes and sizeof(friends[0])


calculates the first element’s size in bytes. By dividing the array size by the
element’s size, we were able to determine the number of elements that
exist within the array. Note that it doesn’t matter whether we calculate the
first element’s size or the second’s since all of the elements are of the same
size (32 bytes each).

Looping Through the Elements


Now that you can determine number of elements within an array, you can
loop through the array to output each element individually.

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

for (int i = 0; i < sizeof(friends) / sizeof(friends[0]); i++) {


cout << friends[i] << endl;
}

challenge

What happens if you:


add "Kate" as an element to the array right after "Jen"?
remove "Alan" and "Bob" from the array?

Notice how sizeof(friends) / sizeof(friends[0]) continues to keep track


of how many elements are in our array even though we’ve made several
changes.
Enhanced For Loop

Using an Enhanced For-Loop


There is a special type of for loop that can be used with arrays called an
enhanced for loop. An enhanced for loop, also known as a range-based
for loop, can be used to iterate through array elements without having to
refer to any array indices. To use an enhanced for loop, you need the
following:
* The keyword for followed by parentheses ().
* A typed iterating variable followed by colon : followed by the array
name.
* Note that the iterating variable must be of the same type as the array.
* Any commands that repeat within curly braces {}.
* Note that when using an enhanced for loop, you can print the iterating
variable itself without using brackets [].

string friends[] = {"Alan", "Bob", "Carol", "David", "Ellen",


"Fred", "Grace", "Henry", "Ian", "Jen"};

for (string i : friends) {


cout << i << endl;
}

challenge

What happens if you:


change cout << i << endl; in the code above to cout <<
friends[i] << endl;?
copy the original code but change string i to int i?
important

IMPORTANT
One of the main differences between a regular for loop and an
enhanced for loop is that an enhanced for loop does not refer to any
index or position of the elements in the array. Thus, if you need to
access or modify array elements, you cannot use an enhanced for
loop. In addition, you cannot use an enhanced for loop to iterate
through a part of the array. Think of an enhanced for loop as an all-or-
nothing loop that just prints all of the array elements or nothing at all.
Also note that the iterating variable type must match the array type.
For example, you cannot use for (int i : friends) since friends is a
string array and i is an integer variable. Use for (string i : friends)
instead.
Helpful Array Algorithms

Array Algorithms
In addition to being used with loops, arrays can also be used with
conditionals to help with tasks such as searching for a particular element,
finding a minimum or maximum element, or printing elements in reverse
order.

Searching for a Particular Element

string cars[] = {"Corolla", "Camry", "Prius", "RAV4",


"Highlander"};
string Camry = "A Camry is not available."; //default string
value

for (string s : cars) { //enhanced for loop


if (s == "Camry") { //if "Camry" is in array
Camry = "A Camry is available."; //variable changes if
"Camry" exists
}
}

cout << Camry << endl; //print whether Camry exists or not

challenge

What happens if you:


delete "Camry" from the cars array?
try to modify the code above so that the algorithm will look for
Prius in the array and will print A Prius is available. if Prius is
an element and A Prius is not available. if it is not an element.

Sample Solution
string cars[] = {"Corolla", "Camry", "Prius", "RAV4",
"Highlander"};
string Prius = "A Prius is not available.";

for (string s : cars) {


if (s == "Prius") {
Prius = "A Prius is available.";
}
}

cout << Prius << endl;

Finding a Minimum or Maximum Value

int grades[] = {72, 84, 63, 55, 98};


int min = grades[0]; //set min to the first element in the array

for (int i : grades) { //enhanced for loop


if (i < min) { //if element is less than min
min = i; //set min to element that is less
}
}
//elements are not modified so enhanced for loop can be used

cout << "The lowest grade is " << min << endl; //print lowest
element

challenge

What happens if you:


replace 72 in the int array with 42?
try to modify the code so that the algorithm will look for the
maximum element instead?

Sample Solution
int grades[] = {72, 84, 63, 55, 98};
int max = grades[0];

for (int i : grades) {


if (i > max) {
max = i;
}
}

cout << "The highest grade is " << max << endl;

Printing Elements in Reverse Order

string letters[] = {"A", "B", "C", "D", "E"};


int elements = sizeof(letters) / sizeof(letters[0]); //number of
elements

//start at index 4, then decrement by 1 until i < 0, then stop


for (int i = elements - 1; i >= 0; i--) {
cout << letters[i] << endl;
}

//regular for loop needed to access each element index


Learning Objectives: Vector Basics

Create an empty vector

Add and remove vector elements

Modify vector elements

Iterate through vector using both a regular for loop and


an enhanced for loop

Determine vector output

Determine key differences between vectors and arrays


Creating a Vector

What Is a Vector?
Although arrays are very useful for data collection, they are considered
static, meaning once they are created, you cannot add or remove elements
from them without changing the way they are initialized. Vectors, on the
other hand, are dynamic, meaning you can make changes to them while
the program is running. Vectors are particularly helpful when you don’t
know how large your collection of elements will become. Since vectors are
dynamic, you can add and remove elements later on if needed. In order to
use vectors, you must include #include <vector> in the header of your
program. For convenience, the program file to your left already contains
the included statement.

Vector Creation
To create a vector, you need to include the following:
* The keyword vector followed by the data type in angle brackets <>.
* A variable name that refers to the vector.
* The number of elements the vector can hold within parentheses ().

vector<int> numbers(3);

cout << numbers << endl;

important

IMPORTANT
When you try to print an array reference variable, you will get the
array’s memory address. However, this is not the case for vectors.

To print an element within the vector, use the at() function and specify the
index of the position of the element you wish to print within the
parentheses.
vector<int> numbers(3);

cout << numbers.at(0) << endl;

Similar to arrays, the first index or position of the vector also starts at index
0. Thus, numbers.at(0) refers to the element at the first position in the
vector, which currently does not contain any initialized elements. When a
vector is declared without any initialized elements, the system will
populate the vector with 0 as elements by default. This is common across
vectors of many data types except strings. Additionally, if you try to output
an element at an index that does not exist, you will get an out_of_range
error message.

vector<int> numbers(3);

cout << numbers.at(3) << endl;


//index 3 refers to the fourth element, not third, which doesn't
exist

Determining Vector Size


Vectors use the function size() to determine the number of elements that
exist instead of the operator sizeof() which is used for arrays. Note their
slight difference in syntax and usage.

vector<int> numbers(3);
int digits[3];

cout << numbers.size() << endl;


cout << sizeof(digits) / sizeof(digits[0]) << endl;

challenge

What happens if you:


remove 3 within vector<int> numbers(3);?
remove 3 within int digits[3];?
important

IMPORTANT
In both arrays and vectors, you must specify how many elements you
expect them to hold. Otherwise, you will not be able to determine their
size. However, if you initialize the array or vector upon declaration,
then you don’t have to specify the number of elements since the system
can determine that automatically.
Adding and Removing Elements

Adding Vector Elements


To add elements to the vector, simply use the push_back() function. The
push_back() function will add whatever element that is specified inside
parentheses () to the end of the vector. If an element is added to an empty
vector such as vector<int> numbers(0), that element will be the first and
only element in the vector.

vector<int> numbers(0); //vector with no elements


numbers.push_back(50); //add 50 as an element to end of vector

cout << numbers.at(0) << endl; //50 becomes first and only
element

Note that the push_back() function does not replace elements.

vector<int> numbers(2); //vector with 2 uninitialized elements


numbers.push_back(50); //add 50 as an element to end of vector

cout << numbers.at(0) << endl; //first uninitialized element


cout << numbers.at(1) << endl; //second uninitialized element
cout << numbers.at(2) << endl; //50 is the third element now

challenge

What happens if you:


change numbers.push_back(50); in original code to
numbers.push_back(true);?
change numbers.push_back(50); in original code to
numbers.push_back(50.99);?
change numbers.push_back(50); in original code to
numbers.push_back("50.99");? Note: “50.99”
important

IMPORTANT
Arrays are strict when it comes to data type compatibility, however,
vectors are more flexible. Between the four common data types, string
is the only type that cannot be associated with the other three in a
vector. Integers, doubles, and booleans are all compatible with each
other. Remember, in C++, true is 1 and false is 0.

In addition, when doubles are converted into integers, their decimal


value get eliminated. This is why pushing 50.99 into an int vector
causes it to turn into 50 without the decimal value.

To add an element to a specific index in the vector, you can use the
insert() along with the begin() functions like below.

vector<int> numbers(2);
numbers.insert(numbers.begin()+1, 50); //add 50 to index 1
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl;
cout << numbers.at(2) << endl;

numbers.insert(numbers.begin()+1, 100); //add 100 to index 1


cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl;
cout << numbers.at(2) << endl; //50 now becomes index 2

challenge

What happens if you:


change numbers.insert(numbers.begin()+1, 50); in the original
code to numbers.insert(numbers.begin()+2, 50);?
change numbers.insert(numbers.begin()+1, 100); in the original
code to numbers.insert(numbers.begin(), 100);?
important

IMPORTANT
The begin() function always refer to the first position in the vector,
which is also the 0th index. If you want to refer to the 1st index, use
begin()+1. For the 2nd index, use begin()+2, so on and so forth.

Removing Vector Elements


To remove an element from the end of a vector, use the pop_back(). Note
that using pop_back will remove the element and its index, thus decreasing
the size of the vector by 1.

vector<int> numbers(0); //empty vector


numbers.push_back(50); //add 50 to vector
numbers.push_back(100); //add 100 to vector
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl << endl;

numbers.pop_back(); //remove last element vector


cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl; //100 has been deleted completely

challenge

What happens if you:


remove cout << numbers.at(1) << endl; from the original code?

To remove an element from a specific index in the vector, use the erase()
function and specify the index you want to erase with begin(). When an
element and its index is removed from the vector, all of the elements to its
right will be moved one place to the left.
vector<int> numbers(0); //empty vector
numbers.push_back(50); //add 50 to vector
numbers.push_back(100); //add 100 to vector
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl << endl;

numbers.erase(numbers.begin()); //removes 50
cout << numbers.at(0) << endl;
cout << numbers.at(1) << endl; //no longer exists

challenge

What happens if you:


remove cout << numbers.at(1) << endl; from the original code?
change numbers.erase(numbers.begin()); from the original code to
numbers.erase(numbers.begin()+1);?
Modifying Elements

Modifying Vector Elements


To modify vector elements, use the at() method to specify the index
number and then assign a new element to it.

vector<string> contact(0);
contact.push_back("First name");
contact.push_back("Last name");
contact.push_back("Phone number");
cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

contact.at(2) = "Email"; //change element at index 2 to "Email"


cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

challenge

What happens if you:


add contact.at(1) = "Nick name"; to the line directly before
contact.at(2) = "Email";?

Initializing Vector Elements


It is possible to initialize elements inside a vector without constantly using
push_back(). The following code will produce the same result as the
original code above.
vector<string> contact{"First name", "Last name", "Phone
number"};
cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

contact.at(2) = "Email"; //change element at index 2 to "Email"


cout << contact.at(0) << " "
<< contact.at(1) << " "
<< contact.at(2) << endl;

When initializing elements within a vector, you do not specify the number
of elements in parentheses. The system will automatically know how many
elements are being added to the vector. The initialized elements should be
in curly braces {} and separated by commas ,.
Iterating a Vector

Iterating Vector Elements


Iterating through a vector is very similar to iterating through an array. The
main difference is that in a vector, we use at() to access the elements
instead of brackets []. Both of the code blocks below use a regular for to
produce the exact same results. The first code block contains an array and
the second contains a vector.

//iterating through an array


int grades[] = {85, 95, 48, 100, 92};

for (int i = 0; i < sizeof(grades)/sizeof(grades[0]); i++) {


cout << grades[i] << endl;
}

//iterating through an vector


vector<int> grades{85, 95, 48, 100, 92};

for (int i = 0; i < grades.size(); i++) {


cout << grades.at(i) << endl;
}

Enhanced For Loop in Vector


We can also use an enhanced for loop, or range-based for loop, to iterate
through a vector.

//iterating a vector with Enhanced For Loop


vector<int> grades{85, 95, 48, 100, 92};

for (auto i : grades) { //can use int or auto for iterating


variable!
cout << i << endl;
}
important

IMPORTANT
When using an enhanced for loop for a vector, you must label the
iterating variable accordingly. If your elements are of type int then
your iterating variable must also be int. If the elements are strings
then your variable must be typed as string. However, you can always
use auto to force the variable to match your element type.
Vector vs. Array

Vector vs. Array


Which one is better: vector or array? The answer is, it really depends. If you
know how many elements you need in your collection and you don’t intend
on changing the order of those elements, then it is better to use an array.
On the other hand, if you don’t know how many elements you need and
want to modify the order of elements later on, then it is better to use a
vector.

Although an array is shorter to write and arguably easier to use, it is static,


meaning it is not possible to add additional elements to the array after it
has already been initialized. In contrast, a vector is more dyanamic,
meaning you can add, remove, and reorganize elements as needed later on.

Here is a table showing the differences between vectors and arrays. Note
that type stands for data type. Also note that var stands for vector or array
name, num stands for an integer number, index stands for index or position
number, and element stands for a vector or array element.

Method/Types Vector Array


vector<type> var(num) or type var[num] or type
Create vector<type> var{element, var[] = {element,
element…} element…}

Find number of
var.size() sizeof(var)/sizeof(var[0])
elements
Access an
var.at(index) var[index]
element
Modify an
var.at(index) = element var[index] = element
element
var.push_back(element) or
Add an element var.insert(var.begin()+index, n/a
element)

Remove an var.pop_back() or
n/a
element var.erase(var.begin()+index)

for (int i = 0; i <


for (int i = 0; i < var.size();
for loop sizeof(var)/sizeof(var[0]);
i++) {cout << var.at(i);}
i++) {cout << var[i];}
Enhanced for for (type i : var) {cout <<
for (type i : var) {cout << i}
loop i}
Common integer, double, boolean, int, double, boolean,
compatible strings strings
types

Using Both a Vector and Array


Vectors and arrays can be used in tandem with each other. For example,
the following code keeps track of the top five students in a class.

string top[] = {"First: ", "Second: ", "Third: ", "Fourth: ",
"Fifth: "};
vector<string> names(0);

names.push_back("Alan");
names.push_back("Bob");
names.push_back("Carol");
names.push_back("David");
names.push_back("Ellen");

for (int i = 0; i < 5; i++) {


cout << top[i] << names.at(i) << endl;
}

challenge

Without deleting any existing code, try to:


switch Alan and Carol’s places.
replace David with Fred.
make Grace get “Fifth” place and remove Ellen from the list.

Sample Solution
string top[] = {"First: ", "Second: ", "Third: ", "Fourth: ",
"Fifth: "};
vector<string> names(0);

names.push_back("Alan");
names.push_back("Bob");
names.push_back("Carol");
names.push_back("David");
names.push_back("Ellen");

names.at(0) = "Carol"; //switch Alan with Carol


names.at(2) = "Alan"; //and vice versa

names.at(3) = "Fred"; //Fred replaces David

names.insert(names.begin()+4, "Grace"); //Grace takes Ellen's


place
names.pop_back(); //Ellen's "Sixth" place gets removed

for (int i = 0; i < 5; i++) {


cout << top[i] << names.at(i) << endl;
}
Helpful Vector Algorithms

Vector Algorithms
Like arrays, vectors can be used to search for a particular element and to
find a minimum or maximum element. Additionally, vectors can reverse
the order of elements rather than just simply printing the elements in
reverse order.

Searching for a Particular Element

vector<string> cars(0);
string Camry = "A Camry is not available."; //default string
value

cars.push_back("Corolla");
cars.push_back("Camry");
cars.push_back("Prius");
cars.push_back("RAV4");
cars.push_back("Highlander");

for (auto a : cars) { //enhanced for loop


if (a == "Camry") { //if "Camry" is in vector
Camry = "A Camry is available."; //variable changes if
"Camry" exists
}
}

cout << Camry << endl; //print whether Camry exists or not

challenge

What happens if you:


add cars.erase(cars.begin()+1); to the line directly below
cars.push_back("Highlander");?
try to modify the code above so that the algorithm will look for
Prius in the array and will print A Prius is available. if Prius is
an element and A Prius is not available. if it is not an element.
Sample Solution

vector<string> cars(0);
string Prius = "A Prius is not available.";

cars.push_back("Corolla");
cars.push_back("Camry");
cars.push_back("Prius");
cars.push_back("RAV4");
cars.push_back("Highlander");

for (auto a : cars) {


if (a == "Prius") {
Prius = "A Prius is available.";
}
}

cout << Prius << endl;

Finding a Minimum or Maximum Value

vector<int> grades(0);
grades.push_back(72);
grades.push_back(84);
grades.push_back(63);
grades.push_back(55);
grades.push_back(98);

int min = grades.at(0); //set min to the first element in the


array

for (auto a : grades) { //enhanced for loop


if (a < min) { //if element is less than min
min = a; //set min to element that is less
}
}
//elements are not modified so enhanced for loop can be used

cout << "The lowest grade is " << min << endl; //print lowest
element
challenge

What happens if you:


add grades.at(0) = 42; to the line directly below
grades.push_back(98);?
try to modify the code so that the algorithm will look for the
maximum element instead?

Sample Solution

vector<int> grades(0);
grades.push_back(72);
grades.push_back(84);
grades.push_back(63);
grades.push_back(55);
grades.push_back(98);

int max = grades.at(0);

for (auto a : grades) {


if (a > max) {
max = a;
}
}

cout << "The highest grade is " << max << endl;

Reversing the Order of Elements


vector<string> letters(0);
letters.push_back("A");
letters.push_back("B");
letters.push_back("C");
letters.push_back("D");
letters.push_back("E");

int original = letters.size(); //original size

//regular for loops needed to access element indices

for (int i = letters.size() - 1; i >= 0; i--) {


letters.push_back(letters.at(i));
} //add elements in reverse order to the vector

for (int j = 0; j < original; j++) {


letters.erase(letters.begin());
} //remove all the original elements

//enhanced for loop can be used for just printing


for (auto a : letters) {
cout << a << " "; //print all new vector elements
}

important

IMPORTANT
Note that we used letters.erase(letters.begin()) which causes the
system to delete both the element and the index. Thus, the next
element in the vector becomes the new 0th index which we want to
continue to delete.
Learning Objectives: 2D Arrays

Create and initialize a 2D array

Access and modify 2D array elements

Iterate through 2D arrays using both a regular for loop


and an enhanced for loop

Determine 2D array output


Creating a 2D Array

An Array Inside Another Array


An array inside another array is called a 2D array. A 2D arrays is symbolic
of a table where there are rows and columns. The first index number
represents the row position and the second index number represents the
column position. Together, the row and column indices enable elements to
be stored at specific locations.

.guides/img/2DArray

string names[3][5];

2D Array Syntax

Array type followed by a name for the 2D array followed by two empty
pairs of brackets [][].
The number of rows goes inside the first pair of brackets and the
number of columns goes inside the second pair of brackets.

Why Array Inside Array?


The way 2D arrays store elements is a little unique. Rather than creating an
actual table like shown above, each initial row of the 2D array actually
refers to another column array. This is why a 2D array is considered to be
an array inside of another array.
.guides/img/2DArrayReference

To determine the number of rows and columns in the 2D array, we can use
the sizeof() operator like we did for arrays.

string names[3][5];

cout << sizeof(names) / sizeof(names[0]) << " rows" << endl;


cout << sizeof(names[0]) / sizeof(string) << " columns" << endl;

important

IMPORTANT
Note that when determining column length, you must refer to the 2D
array’s 0th row index. For example, names[0] doesn’t just refer to the
first element in the row, it also refers to the entire column of elements.
See image above.

sizeof(names[0]) calculates the size of the entire column while


sizeof(string) calculates the size of one string. Thus, dividing the two,
sizeof(names[0]) / sizeof(string), will calculate how many string
elements there are.
Accessing and Modifying a 2D
Array

2D Array Access
To access and modify elements inside a 2D array, you need to specify the
row and column indices at which the elements are located. For example
names[1][2] refers to the element that’s at row index 1 and column index 2.

.guides/img/2DArray

Below is a code block showcasing a 2D array that contains fifteen P.O. Box
names from a postal office. Note that you can initialize the elements inside
your 2D array just like how you initialize elements inside a regular array.
Each column array is separated by curly braces {} as well as a comma ,.

string names[ ][5] = { {"Alan", "Bob", "Carol", "David",


"Ellen"},
{"Fred", "Grace", "Henry", "Ian", "Jen"},
{"Kelly", "Liam", "Mary", "Nancy",
"Owen"} };

cout << names[1][2] << endl;


challenge

What happens if you:


change names[1][2] from the original code to names[2][1]?
change names[1][2] from the original code to names[3][0]?

important

IMPORTANT
Note that you must declare the number of elements within the column
brackets. You can leave the row brackets empty, but you cannot leave
the column brackets empty. Also, when you try to print an element that
is outside of the row/column range, the system will either print
random memory data or nothing at all.

2D Array Modification
To modify elements within a 2D array, simply access the element and
assign another element to it.

string names[3][5] = { {"Alan", "Bob", "Carol", "David",


"Ellen"},
{"Fred", "Grace", "Henry", "Ian", "Jen"},
{"Kelly", "Liam", "Mary", "Nancy",
"Owen"} };

cout << names[1][2] << endl;

names[1][2] = "Harry";
cout << names[1][2] << endl;

challenge

What happens if you:


change all names[1][2] within the code above to names[0][0]?
change "Harry" within your current code to "Amy"?
Iterating a 2D Array

2D Array Iteration
To iterate through a 2D array, we can use two for loops, one nested inside
another. The outer for loop is for the rows while the inner for is for the
columns.

int digits[3][3] = { {1, 2, 3},


{4, 5, 6},
{7, 8, 9} };

int row = sizeof(digits) / sizeof(digits[0]); //number of rows


int col = sizeof(digits[0]) / sizeof(int); // number of columns

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
cout << digits[i][j] << endl;
}
}

Code Visualizer

challenge

What happens if you:


change all sizeof(digits[0]) from the code above to
sizeof(digits[1])?
remove << endl from the code?

Code Visualizer

Note that all of the columns’ lengths are the same, there are 3 columns for
each row. Therefore, it doesn’t matter if we use digits[0], digits[1], or
digits[2] when calculating the number of elements in each row and
column. Also note that using << endl prints the elements vertically while
removing it prints the elements horizontally. To print the elements so that
the columns stay together but the rows separate, we can try something like
this:
int digits[3][3] = { {1, 2, 3},
{4, 5, 6},
{7, 8, 9} };

int row = sizeof(digits) / sizeof(digits[0]);


int col = sizeof(digits[0]) / sizeof(int);

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
if (j == col - 1) {
cout << digits[i][j] << endl;
}
else {
cout << digits[i][j] << " ";
}
}
}

Code Visualizer

The if conditional forces the elements to be printed with a newline every


time the iterating variable reaches the end of the column index. Otherwise,
the elements will be printed with a space instead.

2D Array with Enhanced For Loop


Like arrays and vectors, 2D arrays can also make use of the enhanced for
loop.

int digits[3][3] = { {1, 2, 3},


{4, 5, 6},
{7, 8, 9} };

for (auto &i : digits) {


for (int j : i) {
if ((j == 3) | (j == 6) | (j == 9)) {
cout << j << endl;
}
else {
cout << j << " ";
}
}
}

Code Visualizer
You may have noticed that the outer loop contains for (auto &i : digits).
Unlike a regular array where we can access the first element by locating
just one index, we need two indices in order to access elements within a 2D
array. The &i creates a reference iterating variable that can refer to the 2D
array. We type it as auto because doing so will cause the system to force the
variable to match the 2D array type. In fact, we can always use auto to type
variables to cause them to match the data that they refer to. For example,
we can use for (auto j : i) for the inner loop instead of using int.

Also note that we cannot use an enhanced for loop to manipulate array
indices. Our iterating variable goes through the 2D array and takes on each
element value rather than each element index. This is why we have the
conditional statement if ((j == 3) | (j == 6) | (j == 9)) rather than
if (j == col - 1).
Lab: Arrays

Tutorial Lab 1: Using an Array


An array is a data structure that groups data together into a collection of
elements. Each element has its own index or position within the array.
These elements can be initialized, accessed, modified, and printed. Copy the
code below into the text editor on the left. Then click on the TRY IT button
to see the resulting output.

string classes[] = {"Math", "English", "Science", "Social


Studies", "Spanish"};

classes[4] = "French";

for (int i = 0; i < sizeof(classes)/sizeof(classes[0]); i++) {


cout << classes[i] << endl;
}

Program Summary

1. An array called classes is created and initialized with elements


(i.e. "Math", "English", etc.).
2. At index 4, "Spanish" is modified and replaced with "French". Keep in
mind that array indices start at 0, not 1.
3. A for loop iterates through the elements in the array. It starts at index 0,
ends right before index 5, and increments by 1 after each iteration.
4. Each element from index 0 through index 4 gets printed with a newline.
Lab: Vectors

Tutorial Lab 2: Using a Vector


A vector is another data structure that has many of the same functionalities
as an array. However, they are more flexible in the functions that they are
able to use. These functions include adding and removing elements within
the vector, meaning vectors can dynamically change their size, something
arrays cannot do. Copy the code below into the text editor on the left. Then
click on the TRY IT button to see the resulting output.

vector<string> veggies(0);
veggies.push_back("carrot");
veggies.push_back("tomato");
veggies.push_back("celery");
veggies.push_back("spinach");

veggies.erase(veggies.begin()+1);
veggies.at(1) = "potato";

for (auto a : veggies) {


cout << a << endl;
}

Program Summary

1. A vector called veggies is created.


2. carrot, tomato, celery, and spinach are added to the vector as elements.
3. The element at index 1 (tomato) is removed.
4. The element potato replaces the element at index 1, which is currently
celery since tomato was deleted previously.
5. An enhanced for loop is used which creates an iterating variable a
(typed auto) to take on the value of each element.
6. Each element a is then printed with a newline.
Lab: 2D Arrays

Tutorial Lab 3: Using a 2D Array


A 2D array is an array inside another array. This data structure can be
visually compared to a table where there are rows and columns and each
element exists inside each “cell.” To access or modify elements, both the
row index and column index are needed. Like arrays, 2D arrays are static
so elements cannot be added or removed after initialization.

int coordinates[5][2] = { {-4, 3},


{2, 1},
{0, -8},
{-11, 9},
{-5, -7} };

int row = sizeof(coordinates) / sizeof(coordinates[0]);


int col = sizeof(coordinates[0]) / sizeof(int);

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
if (j == 1) {
cout << coordinates[i][j] << endl;
}
else {
cout << coordinates[i][j] << " ";
}
}
}

Code Visualizer
Lab Challenge: 2D Chessboard

2D Chessboard
You are trying to create a chessboard representation using the alphabetical
letters O and X. The O represents the lighter spaces while the X represents
the darker spaces.

OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO

So far you have the following code within the text editor to your left:
#include <iostream>
using namespace std;

int main() {

string chessboard[8][8];

int row = sizeof(chessboard) / sizeof(chessboard[0]);


int col = sizeof(chessboard[0]) / sizeof(string);

//add code below this line

//add code above this line

for (int i = 0; i < row; i++) {


for (int j = 0; j < col; j++) {
if (j == col - 1) {
cout << chessboard[i][j] << endl;
}
else {
cout << chessboard[i][j];
}
}
}

return 0;

Chessboard Challenge
challenge

Assignment:
For this challenge, you will use your knowledge of 2D arrays to
produce the chessboard pattern:

OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO
OXOXOXOX
XOXOXOXO

Requirement:
Your program cannot make any changes to the existing code in the
program. If you do, you will not earn any credit for this challenge. If
you accidentally delete any existing code, you can copy the original
code shown above back into your program.

Hint: It is probably much easier to use nested for loops in your code to
populate the 2D array with either O or X than to go through each (row,
column) index to modify the elements.
Learning Objectives: Pointer Basics

Define what a pointer is

Declare a pointer

Apply the reference or address operator “&”

Apply the dereference or content operator "*"


What Is a Pointer?

Pointer Introduction
A pointer is a data type that stores a memory address of another piece of
data. Much like how an array points to all of its elements as a collection,
pointers point to the memory address of the data that they are associated
with.

.guides/img/PointerBasics

The picture above shows how pointers work. A pointer is like a key that
stores the address of the locker that it is associated with. This association
also enables the pointer to gain access to the content of what’s inside the
locker.

The advantage of using a pointer is that you do not need to worry about the
value of the data that the pointer is pointing to. Thus, if the data ever
changes its value, the pointer will still be able to access the new data as
long as the pointer still points to the data’s memory address.
Declaring a Pointer

Pointer Declaration
All pointers have a data type and a name that they are referred to. To
declare a pointer, you need to have the following syntax in order:

The data type of the pointer (e.g. int, string, etc.).


An asterisk symbol *.
A name for the pointer.

int* p;

cout << p << endl;

challenge

What happens if you:


change int* p; in the original code to double* p;, bool* p;, or
string* p;?
change int* p; in the original code to int *p;?
change int* p; in the original code to int *p = 2;?

important

IMPORTANT
The asterisk symbol can be placed anywhere between the end of
the data type (i.e. int) and the variable name (i.e. p). int* p;, int
*p, and int * p all work the same way.

Pointers can only be assigned a memory address, which is why


trying to assign 2 to a pointer will result in an error.

Pointers that are not assigned a memory address will have a default
output of 0, also referred to as null pointers.
Reference Operator

Pointer Reference
A pointer can only be assigned a memory address. They cannot be
assigned values that are int, double, string, etc. A memory address is
denoted with the & symbol, called the reference operator, and they go in
front of the variable that the address is associated with.

int a = 2;
int* p = &a;

cout << p << endl;

Code Visualizer

challenge

What happens if you:


run the same exact code again by clicking TRY IT?
change int* p = &a;; in the original code to int* p = & a;?

Code Visualizer

important

IMPORTANT
Memory is dynamic in C++ so whenever programs are compiled or
executed again, they will often output memory addresses that are
different from before.

Though memory address is dynamic, once a pointer has been


assigned a memory address, that association remains until the
program is re-compiled or re-executed.
Dereference Operator

Pointer Dereference
Every memory address holds a value and that value can be accessed by
using the dereference operator. The dereference operator is denoted by
the asterisk symbol *.

int a = 5; //regular int variable set to 5


int* p = &a; //int pointer points to a's memory address

cout << *p << endl; //dereference p to print its content

Code Visualizer

challenge

What happens if you:


change int a = 5; in the original code to int a = 50;?
change int* p = &a; in the original code to string* p = &a;?

Code Visualizer

important

IMPORTANT
A pointer can only be assigned a memory address of a variable that
holds a value of the same type as the pointer. For example, if &a is
the memory address of an int variable, then you cannot assign it to
a string pointer (string* p = &a).

Though memory address is dynamic, once a pointer has been


assigned a memory address, that association remains until the
program is re-compiled or re-executed.
Pointer to another Pointer
It is possible to have a pointer point to another pointer. To assign the
memory address of a pointer to a new pointer, that new pointer must be
denoted with two asterisk symbols **.

int a = 5;
int* p = &a;
int** p2 = &p;

cout << *p << endl;


cout << **p2 << endl;

Code Visualizer

challenge

What happens if you:


change int a = 5; in the original code to int a = 100;?
change cout << **p2 << endl; in the original code to cout << *p2
<< endl;?

Code Visualizer

important

IMPORTANT
Dereferencing a new pointer to an old pointer will return the memory
address of the old pointer. If that pointer is dereferenced again, then
the value of the variable that the old pointer pointed to will be
returned. For example, **p2 and *p both returned 5 because p2 points
to p which points to a which equals 5.
.guides/img/PointerTable

challenge

Fun Fact:
If you dereference an array, it will return only the first element in the
array.

int array[] = {24, 52, 97};

cout << *array << endl;


Why Use Pointers?

Array Memory Usage


Before we can see how useful pointers can be, let’s take a look at how
memory is used within an array:

char names[3][6] = { "Alan",


"Bob",
"Carol" };

for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {


cout << names[i] << endl;
}

Code Visualizer

Remember: The row index [3] is optional but the column index [6] is
mandatory.

Why is the column index 6 instead of 5?


When working with a string of characters, the last character is always a
special character known as a null character. This character is often
referred as NUL or \0. Therefore, the maximum character length within this
array is ‘C’,‘a’,‘r’,‘o’,‘l’,‘\0’, which has 6 characters. This is why to
be able to store all of the characters, the column index must be set to 6.

The code above creates an array of characters where the row index [3]
refers to the three starting characters A for Alan, B for Bob, and C for Carol,
and the column index 6 refers to how many character each of the rows can
hold which also includes the null characters (NUL or \0). Notice how the null
characters also take up memory space.
.guides/img/ArrayNullCharacter

Here, we know how long the names would be, so we were able to budget
the right amount memory for them. However, what if we didn’t? In such a
case, we would have to assign additional space for our characters,
something larger, like 20 for example. That way, if the name Carol was a
mistake and it was actually supposed to be ChristopherJones, we can feel
more confident that the array will still be able to hold all of the characters.
Unfortunately, this causes more memory to be wasted as depicted in the
image below.

.guides/img/ArrayWasteMemory

Pointer Usage
This is where pointers come in handy because they can help the system
save memory. When using pointers for character arrays, the pointers will
only point to the 3 leading characters A, B, and C. You do not need to specify
the column index. Note that C++ requires the keyword const for pointers
that point to characters within an array. This forces the characters to
remain intact and prevents the pointer from potentially pointing
elsewhere.
const char* names[] = { "Alan",
"Bob",
"ChristopherJones" };

for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {


cout << names[i] << endl;
}

Code Visualizer

.guides/img/PointerArray

Notice how we did not have to include any index values, which means the
potential for wasting memory can be avoided. All we needed was to
reserve enough memory for the creation of 3 pointers.
Lab: Pointer Operators

Tutorial Lab: Reference and Dereference


Operators
Pointers are used to store the memory address of a particular variable. Two
important operators associated with pointers are the reference & and the
dereference operators *. The & operator returns the memory address of a
variable and the * operator returns the value or content of the variable
being pointed to.

bool b = true;
bool* p = &b;

cout << p << endl; //prints b's memory address


cout << boolalpha << *p << endl; //prints b's value

A pointer can also point to another pointer. When doing so, the new
pointer will be denoted with two asterisk symbols **. ** is also used to
dereference a pointer twice.

bool b = true;
bool* p = &b;
bool** p2 = &p; //p2 points to p

cout << p2 << endl; //prints p's memory address


cout << *p2 << endl; //prints p's content which is b's address
cout << boolalpha << **p2 << endl;
//p2 is dereferenced twice to print b's value
Lab Challenge: Pointer Keys

Pointer Keys
You are trying to come up with a set of pointers or keys that, when referred
to, will be able to tell you the age of each of your family members. For
example, the pointer amy should be associated with the variable age1.

So far you have the following information in your code:

#include <iostream>
using namespace std;

int main() {

int age1 = 12;


int age2 = 31;
int age3 = 29;
int* amy;
int* bob;
int** carol;

//add code below this line

cout << *amy << endl; //do not edit

cout << *bob << endl; //do not edit

cout << **carol << endl; //do not edit

//add code above this line

return 0;

Pointer Challenge
challenge

Assignment:
Your task is to associate the pointers within the code to their respective
variables. The output of your program should produce:

Amy's age is: 12


Bob's age is: 31
Carol's age is: 29

Requirement:
To receive credit for the challenge, you need to do the following:
* Only add to the existing code, do not make any changes, otherwise,
you will not receive credit for your work. If you accidentally delete any
existing code, you can copy the original code shown above back into
your program.

You must use the pointers amy, bob, and carol in your code and
assign the pointers to their appropriate data.

NOTE that the pointer carol is a pointer to another pointer. You


will need to create a new pointer in your code to make the
association.
Learning Objectives: String Basics

Identify the three properties of strings

Understand the meaning of mutability

Determine if a string is present in another string and at


what index

Print a string from the start index to end index

Utilize escape characters to add special characters to a


string
String Properties

String Length
We have already seen strings in the “Fundamentals”section. We are going
to dig a little deeper with this data type. All strings have the following
characteristics:

1. Characters - Strings are made up of characters between quotation


marks (previously covered in the “Fundamentals” section).
2. Length - Each string has a length (total number of characters).
3. Index - Each character in a string has a position, called an index.

To calculate the length of a string, use the length() function. This function
will return an integer that is the sum of all of the characters between the
quotation marks.

string my_string = "Hello";


int len_string = my_string.length();

cout << len_string << endl;

challenge

What happens if you:


Change my_string to "Hello world!"?
Change my_string to ""?
Change my_string to "-1"?
Change my_string to "Привет"
important

IMPORTANT
Although each character that you see on a typical keyword usually has
a length of 1, there are other foreign characters that do not follow this
convention. For example, Привет, which stands for Hello in Russian,
actually has a length of 12 instead of 6.

String Index
Previously in the vectors module, we learned that vectors and arrays have
elements that reside in certain positions or indices. A string too has indices
that correspond to the position where each of its character resides. Like
vector and array indices, string indices also start at 0.

.guides/img/StringIndex

Strings & Quotation Marks


Quotation marks are required to declare the value of a string. However,
quotation marks are not a part of the string itself. That is why quotation
marks are not counted with the length() function and why they do not
have an index.

To reference a character, use the string name followed by the at()


function. Within parentheses (), provide the index number of the
character you want the system to return. Alternatively, you can also use
brackets [] to enclose the index number.

.guides/img/StringAtIndex
string my_string = "Hello!";
char character = my_string.at(1);

cout << character << endl;

challenge

What happens if you:


Change char character to my_string.at(my_string.length())?
Change char character to my_string.at(my_string.length()-1)?
Change char character to my_string.at(5)?
Change char character to my_string.at(-1)?
Change char character to my_string[5]?
Change char character to my_string[my_string.length()]?

Note that you cannot use my_string[my_string.length()]. An index


number is needed.
Mutability

Mutability
You now know how to reference each character of a string. What do you
think the code below will do?

string my_string = "House";


my_string.at(0) = "M";

cout << my_string << endl;

If you thought the code above would print Mouse, that would be a logical
guess. However, you see an error. Unlike vectors and arrays where the
characters can be manipulated, string literals are immutable. That means
you cannot change the string literal itself. You can, however, manipulate a
particular character within the string.

string my_string = "House";


my_string.at(0) = 'M';

cout << my_string << endl;

Can you spot the difference between the two code snippets mentioned
above? The difference lies within the double quotes "" and single quotes ''.
You cannot change the string literal, but you can change a character at a
particular index. Thus, my_string.at(0) = 'M' changes the string to Mouse
but my_string.at(0) = "M" does not.

String Re-Assignment
In addition to character manipulation, you can also change the entire
string itself by overwriting it with a new value(s).

string my_string = "House";


my_string = "Mouse";

cout << my_string << endl;


Strings in C++, like other data types, can be re-assigned. The previous
examples on this page are about mutability. That is, changing just a part of
a whole. The current example is about the assignment operator. Re-
assignment replaces the entire value of a variable with a new value. In
conclusion, you can either change one character at a time within a string,
or change the entire string literal by reassigning it.

.guides/img/MutabilityAssignment
Find

The find() Function


The find() function tells you if a character or a string is present in another
string, and if so, at what index it is at. find() returns an integer index if the
character or string is present and 18446744073709551615 if not.

What does 18446744073709551615 mean?


18446744073709551615 is the largest integer value possible in C++. When
find() is called and 18446744073709551615 is returned, it means the system
has searched through all values and cannot locate the specified value.
18446744073709551615 is an unsigned value, but it is equivalent to -1 as a
signed value.

string my_string = "The brown dog jumps over the lazy fox.";

cout << my_string.find("dog") << endl;

challenge

What happens if you:


Change the cout statement to be cout << my_string.find("cat");?
Change the cout statement to be cout << my_string.find("Dog");?
Change the cout statement to be cout << my_string.find(" ");?
Change the cout statement to be cout <<
my_string.find(my_string);?

If you want to start searching for a string or character starting at a


particular index, you can specify the start index number after the specified
string.

string my_string = "The brown dog jumps over the lazy fox.";

cout << my_string.find("he", 4) << endl; //start at index 4


challenge

What happens if you:


Change my_string.find("he", 4) to my_string.find("he", 27)?
Change my_string.find("he", 4) from the original code to
my_string.find("he")?
Substr

The substr() Function


The subst() function returns a portion of the string. Within parentheses (),
provide the index at which you want the string to start followed by a
comma followed by the number of characters you want the string to
include. Note that if you don’t specify the number of characters, the system
will start copying from the start index through to the end of the string. If
you don’t specify the start index, then the system will copy the entire string.
The subst() function does not modify the original string. Instead, it returns
a partial or entire copy of the original string.

.guides/img/StringSubstr

string my_string = "The brown dog jumps over the lazy fox.";
string my_slice = my_string.substr(4, 9);

cout << my_slice << endl;

challenge

What happens if you:


Change my_slice to be my_string.substr(1, 2)?
Change my_slice to be my_string.substr()?
Change my_slice to be my_string.substr(1, 1)?
Change my_slice to be my_string.substr(2)?
Escape Characters

Escape Characters
An escape character is a character that has a different interpretation than
what you see in a string. Escape characters always start with a backslash
(\). The most common escape character is the newline character (\n) which
causes C++ to print on the next line.

string my_string = "Hello\nworld";


cout << my_string << endl;

Escape
Description Example
Character
\\ Prints a backslash cout << "\\" << endl;

Prints a single
\' cout << "\'" << endl;
quote
Prints a double
\" cout << "\"" << endl;
quote
Prints a tab cout << "Hello\tworld" <<
\t
(spacing) endl;

challenge

What happens if you:


Use \n\n instead of \n in the original code?
Replace \n\n in your current code with \t?
Replace \t in your current code with \"?

Quotes Inside Quotes


Imagine that you have this small bit of dialog, And then she said, "Hi
there." and want to store it as a string. Typing "And then she said, "Hi
there."" would cause an error.
.guides/img/StringQuotes

When you use a " to start a string, C++ looks for the next " to end it. To
avoid syntax errors, you can use a double quote to start your string, single
quotes for the inner quote, and end the string with a double quote.

string my_string = "And then she said, 'Hi there.'";


cout << my_string << endl;

challenge

What happens if you:


Replace single quotes (') with double quotes (") and double
quotes(") with single quotes (') in the original code?
Change all quotes to double quotes (")?
Use the escape character \" for the inner quotation marks that
surround Hi there. (e.g. "And then she said, \"Hi there.\"")?
Learning Objectives: String
Functions

Identify the functions and applications of the following


string functions:

find_first_of() & find_last_of()


push_back() & insert()
pop_back() & erase()
replace()
append()
toupper() & tolower()
Find First Of & Last Of

The find_first_of() Function


The find_first_of() function works similarly to how the find() function
does. However, the find_first_of() function will search for any matching
characters specified. For example, given the string "this is his string",
my_string.find_first_of("his") will return 1 because the character h
within his appears first at index number 1. Like the find() function, you
can optionally specify an index number to direct the system where to start
searching.

.guides/img/FindFirstOf

The find_last_of() function


You can use the find_last_of() function to search for a set of characters in
a string that occur last. Here is an example, given the string “this is his
string”, my_string.find_last_of(“his”) will return 15 because the i in his
occurs last at index 15. If you don’t want the system to search the whole
string, you can specify an index as a second parameter to direct the system
where to start searching.

string string1 = "The brown dog jumps over the lazy fox.";
string string2 = "brown";

cout << string1.find_first_of(string2) << endl;


challenge

What happens if you:


Set string2 to "wornb"?
Change the cout statement to string1.find_first_of(string2,
14)?
Set string2 to "axe" and change the cout statement to
string1.find_first_of(string2, 34)?
Set string2 to "i" and change the cout statement to
string1.find_first_of(string2)?

Remember that 18446744073709551615 is equivalent to -1 which also


means not found.
Push Back & Insert

The push_back() Function


In a previous module, you were introduced to vectors. The push_back()
function works the same way in strings as it does in vectors. It adds a
specific character to the end of the string.

string my_string = "Today is Satur";


my_string.push_back('d');

cout << my_string << endl;

challenge

What happens if you:


add the code my_string.push_back("ay"); below
my_string.push_back('d');?
replace my_string.push_back("ay"); with
my_string.push_back('a');?
add the code my_string.push_back('y'); below
my_string.push_back('a');?

The insert() Function


Unfortunately, the push_back() function cannot add multiple characters
(string) to an existing string. However, the insert() function can. Unlike
many functions where specifying the starting index number is optional,
doing so is necessary for insert() to work.

Note that the index specification comes before the string you want the
system to add. For example, my_string.insert(0, "abc") will add the
string abc to the 0th index which is also the beginning of the string. To add
to the end of the string, you can use my_string.length(). Note that you do
not need to subtract 1 from my_string.length() because the system will
add characters starting at the index after the last character of the string.
string my_string = "Today is Satur";
my_string.insert(my_string.length(), "day");

cout << my_string << endl;

challenge

What happens if you:


replace my_string.insert(my_string.length(), "day"); with
my_string.insert(0, "day");?
change the code back to my_string.insert(my_string.length(),
"day"); and add my_string.insert(9, "a good "); below it?
Pop Back & Erase

The pop_back() Function


The pop_back() function removes a single character from the end of a
string. You do not include anything within parentheses ().

string my_string = "Today is my birthday!";


my_string.pop_back();

cout << my_string << endl;

The erase() Function


The erase() function can remove multiple characters from a string or the
entire string itself. To remove the whole string, leave the parentheses ()
empty. Alternatively, you can specify one index number to remove all
characters starting at that index to the end of the string. Specify two index
numbers to start at an index and erase a certain number of characters at
that index forward.

string my_string = "Today is my birthday!";


my_string.erase(my_string.length()-1);

cout << my_string << endl;

challenge

What happens if you:


Replace my_string.erase(my_string.length()-1); with
my_string.erase(12);?
Replace my_string.erase(12); in your current code with
my_string.erase(12, 5);?
Replace my_string.erase(12, 5); in your current code with
my_string.erase();

Why do I see Command was successfully executed.?


When Codio does not detect anything being printed to the console, you will
see the message Command was successfully executed. displayed. The
command my_string.erase() causes the entire string to become empty and
since an empty string has no output, you will see Command was successfully
executed. instead.
Replace

The replace() Function


The replace() function is really a combination of the erase() and insert()
functions. Let’s take a look at an example.

my_string.replace(1, 2, "3")

There are three parameters of interest within replace() above. The 1


represents the index at which we want to start erasing. The 2 tells the
system how many characters to erase starting at index 1. And the "3" is the
string that the system will insert into the string at index 1.

string string1 = "Hello world!";


string string2 = "Codio.";
string string3 = string1.replace(6, 5, string2);
// erase all characters from index 6 plus 5 chars to the right
in string1
// then insert string2 at index 6 within string1

cout << string3 << endl;

challenge

What happens if you:


Change string3 to string1.replace(6, 6, string2)?
Change string3 to string1.replace(2, 3, "y")?
Append

The append() function


An alternative way to concatenate or combine strings is to use the
append() function. The append() function works in the same way as adding
literal strings together using the + operator.

string a = "High";
string b = " Five";

cout << a.append(b) << endl;

challenge

What happens if you:


Change the cout statement to a.append(b + "!")?
Change the cout statement to a.append("Five" + "!")?
Change the cout statement to "High" + " Five" + "!"?
Change the cout statement to a + " Five" + "!"?
Change the cout statement back to a.append(b) and replace string
b = " Five"; with int b = 5;

important

IMPORTANT
NOTE that the append() function is exclusively for strings. Thus, you
cannot include other data types like ints when using append() unless
they are converted to strings first. Additionally, when using the +
operator to combine two strings together, make sure that at least one
of the strings is a string variable. Otherwise, the system will think you
are trying to manipulate a string literal, which is not allowed.
Uppercase & Lowercase

The toupper() Function


The toupper() function returns the uppercase form of a specified character.
Insert the character you wish to convert as a parameter.

Note that by default, toupper() returns the ASCII representation of the


uppercase letter. Thus, you’ll need char to convert the ASCII code into
alphabetical.

.guides/img/StringToUpper

string my_string = "the big brown dog";

cout << char(toupper(my_string.at(0))) << endl;

challenge

What happens if you:


Change the cout statement to
char(toupper(my_string.at(my_string.length()-1)))?
Change the cout statement to char(toupper('t'))?
Change the cout statement to char(toupper(my_string))?

The tolower() Function


The tolower() function returns the lowercase form of a specified character.
It has all of the technicalities that the toupper() function has.

string my_string = "THE BIG BROWN DOG";

cout << char(tolower(my_string.at(1))) << endl;

challenge

What happens if you:


Change the cout statement to
char(tolower(my_string.at(my_string.length()-1)))?
Change the cout statement to char(tolower('B'))?
Change the cout statement to char(tolower('%'))?
Learning Objectives: String
Iteration

Define string iteration

Identify two ways to iterate over a string

Explain the inner workings of string iteration


Iteration: For Loop

Iterating Over Strings


Iterating over a string allows you to deal with each character of a string
individually without having to repeat certain commands. You start with the
character at index 0 and move through the end of the string.

string my_string = "Hello world";

for (int i = 0; i < my_string.length(); i++) {


cout << my_string.at(i);
}

challenge

What happens if you:


Change the value of my_string to
"\u25A3\u25A8\u25D3\u25CC\u25A2"?
Note: Some Unicode characters are not compatible with cout
and/or endl; commands.
Change the value of my_string to "10, 11, 12, 13, 14"?
Change the cout statement to cout << my_string.at(i) << endl;?
Change the cout statement to cout << my_string;?

Note that you can also use a range-based or enhanced for loop to iterate
over strings. Make sure to cast the iterating variable as char!

string my_string = "Hello world";

for (char c : my_string) {


cout << c;
}
Iteration: While Loop

While Loop
String iteration is most often done with a for loop. However, a while can be
used as well.

string my_string = "Calvin and Hobbes";


int i = 0;

while (i < my_string.length()) {


cout << my_string.at(i);
i++;
}

challenge

What happens if you:


Change the loop to while (i <= my_string.length())?
Copy the original code but change the cout statement to cout <<
i;?
Copy the original code but remove i++;?

Comparing While & For Loops

string my_string = "C++";

for (int i = 0; i < my_string.length(); i++) {


cout << my_string.at(i);
}
string my_string = "C++";
int i = 0;

while (i < my_string.length()) {


cout << my_string.at(i);
i++;
}

Above are two ways of iterating through a string. The first way uses the for
loop and the second uses a while loop. Both produces the same result.
However, the for loop is usually preferred because it requires less code to
accomplish the same task. You can also use an enhanced for loop, which
requires the least account of code, but an enhanced while loop does not
exist.
Learning Objectives: String
Comparison
Compare strings with == and !=

Compare strings with compare()


== & !=

Comparing with ==
The == operator can be used with strings just like it is with numbers or
boolean values. Note that without the boolalpha flag, the system will return
1 if true and 0 if false. 1 represents string equality and 0 represents
inequality.

string string1 = "It's Friday!";


string string2 = "It's Friday!";

cout << (string1 == string2);

challenge

What happens if you:


Change the value of string1 to "it's friday!"?
Change the value of string2 to "it\'s friday!"?
Change the cout statement to cout << boolalpha << (string1 ==
string2);?

Comparing with !=
You can also test for string inequality with the != operator.

string string1 = "It's Friday!";


string string2 = "It's Monday.";

cout << (string1 != string2);


challenge

What happens if you:


Change the value of string2 to "It's Friday"?
Change the value of string2 to "It's Friday!"?
Change the cout statement to cout << boolalpha << (string1 !=
string2);?
Compare

Lexicographical Order
In C++, strings can be compared lexicographically, meaning they can be
compared according to how they will appear in the dictionary. You can use
the compare() method to determine which of two strings comes first. A
return value of a negative integer means the first string comes first, a
return value of a positive integer means the second string comes first, and
a return value of 0 means the strings are equal and neither comes first.

string string1 = "apple";


string string2 = "cat";

if (string1.compare(string2) < 0) {
cout << "string1 comes first" << endl;
}
else if (string1.compare(string2) > 0) {
cout << "string2 comes first" << endl;
}
else {
cout << "the strings are equal" << endl;
}

challenge

What happens if you:


Change string2 to "apple"?
Change string2 to "10"?
Change string1 to "2" in your current code?

Why Does “10” Come Before “2”?


When C++ compares strings lexicographically, it compares each character
of the strings one by one from left to right. Since the first character in 10 is
1, and 1 comes before 2, 10 is considered to come before 2 even though
numerically 2 is supposed to come first.
string string1 = "123";
string string2 = "9";

if (string1.compare(string2) < 0) {
cout << "string1 comes first" << endl;
}
else if (string1.compare(string2) > 0) {
cout << "string2 comes first" << endl;
}
else {
cout << "the strings are equal" << endl;
}

challenge

What happens if you:


Change string1 to "apple"?
Change string2 to "Apple" in your current code?
Change string1 to an empty string "" in your current code?

Letters vs. Numbers vs. Empty Strings


Lexicographically speaking, empty strings always come first, followed by
numbers, then uppercase letters, and finally lowercase letters.
Lab 1

Counting Uppercase and Lowercase Characters


You are going to write a program that takes a string and prints out two
messages. One message tells you how many uppercase characters are in the
string. The other message tells how many lowercase characters are in the
string. The program will ignore all numbers and special characters
(punctuation, symbols, etc.).

String Functions

You will need two string functions that were not covered earlier to help
with this project:
* isupper() - Returns an integer greater than 0 if the character is
uppercase, 0 if the character is not.
* islower() - Returns an integer greater than 0 if the character is
lowercase, 0 if the character is not.

Variables

You will need three variables for this project. One variable will count all of
the lowercase characters, another to count the uppercase characters, and
one for the string itself.

int lower_count = 0;
int upper_count = 0;
string my_string = "Roses are Red, Violets are Blue";

Iterating Over the String

The next thing to do is iterate over the string and to check each character of
the string. A enhanced for loop works best.

for (char ch : my_string)

Checking for Uppercase and Lowercase


It does not matter if you check for an uppercase character first or check for
a lowercase character. Let’s start with lowercase characters. Ask if the
character is lowercase and increment the appropriate counting variable.

if (islower(ch)) {
lower_count += 1;
}

What you do not want to do is use an else statement. This will not give you
an accurate count. For example, asking if a special character is lowercase
will return 0. However, that does not mean that it is an uppercase character
either. Special characters are neither uppercase nor lowercase. So use an
else if statement and ask if the character is uppercase. If so, increment
the uppercase counting variable.

else if (isupper(ch)) {
upper_count += 1;
}

Print the Results

The final step is to print the messages with the count values.

cout << "There are " << lower_count << " lowercase characters."
<< endl;
cout << "There are " << upper_count << " uppercase characters."
<< endl;

There should be 4 uppercase characters and 21 lowercase characters.

Code
int lower_count = 0;
int upper_count = 0;
string my_string = "Roses are Red, Violets are Blue";

for (char ch : my_string) {


if (islower(ch)) {
lower_count += 1;
}
else if (isupper(ch)) {
upper_count += 1;
}
}

cout << "There are " << lower_count << " lowercase
characters." << endl;
cout << "There are " << upper_count << " uppercase
characters." << endl;
Lab 2

Reverse a String
You are going to write a program that takes a string and prints it in reverse
order.

Variables

All you need for this program is the string variable and a loop to iterate
through the string.

string my_string = "The brown dog jumps over the lazy fox";

String Iteration

Since we are going to reverse the order of the string, we will need to start at
the end of the string and iterate back to the front. Unfortunately, an
enhanced for loop will not help us in this case because it only iterates from
left to right. However, we can still use a regular for loop.

The for loop should start at the back my_string,length()-1 and run as long
as index is greater than or equal to 0. After each iteration, the iterating
variable should also decrement by 1 to allow the loop to reverse.

for (int i = my_string.length()-1; i >= 0; i--)

Reversing a string comes down to taking the character from the end
printing that first, then go backwards. This will be done by accessing the
indices with at().

my_string.at(i);

Printing the result

All that’s left to do is print. Remember not to include endl or the system
will print a newline after each character.

cout << my_string.at(i);


You should see xof yzal eht revo spmuj god nworb ehT.

Code

string my_string = "The brown dog jumps over the lazy fox";

for (int i = my_string.length()-1; i >= 0; i--) {


cout << my_string.at(i);
}
Lab 3

Swapping the Case of Characters


You are going to write a program that takes a string and prints a new string
where all of the uppercase letters become lowercase, and the lowercase
letters become uppercase.

Variables

You are going to need two string variables. The first string variable
represents the original string and the second represents the modified
string. For now, the modified string can be empty.

string original_string = "THE BROWN DOG JUMPS over the lazy


fox!";
string modified_string;

String Iteration

It does not matter if you start at the beginning of the string or the end for
iteration. An enhanced for loop is the easiest way to iterate through the
original_string. Set the iterating variable as ch.

for (char ch : original_string)

String Functions

You are going to use the isupper() and islower() functions to test if a
character is uppercase or lowercase. In addition, you will be using the
toupper() and tolower() functions to convert characters to their new cases.

Conditional

For consistency, we will test if a character is lowercase first. However, you


may choose to test for uppercase first. It does not matter as long as the
conversion is correct.

if (islower(ch))
If this is true, then append the uppercase version of the character to the
variable modified_string.

modified_string += toupper(ch);

If the conditional is false, then append the lowercase version of the


character to modified_string.

else {
modified_string += tolower(ch);
}

You do not need to worry about special characters. Converting them to


uppercase or lowercase has no effect.

Printing the Results

Once the loop has finished, print both the original string and the modified
string.

cout << "The original string is: " + original_string << endl;
cout << "The modified string is: " + modified_string << endl;

You should see the following output:

The original string is: THE BROWN DOG JUMPS over the lazy fox!
The modified string is: the brown dog jumps OVER THE LAZY FOX!

Code
string original_string = "THE BROWN DOG JUMPS over the lazy
fox!";
string modified_string;

for (char ch : original_string) {


if (islower(ch)) {
modified_string += toupper(ch);
}
else {
modified_string += tolower(ch);
}
}

cout << "The original string is: " + original_string << endl;
cout << "The modified string is: " + modified_string << endl;
Lab 4

Count the Vowels


You are going to write a program that counts the number of vowels that
appear in a string. For the purpose of this exercise, vowels are upper and
lowercase a, e, i, o, u.

Variables

For this project, you will need three variables. One will be the string.
Another will be a char to represent each character of the string. The final
variable will be a count of all the vowels.

string my_string = "The Brown Dog Jumps Over The Lazy Fox";
char ch;
int count = 0;

String Iteration

Use a for loop to iterate through the string. Then set ch to check every
character in the string.

for (int i = 0; i < my_string.length(); i++) {


ch = my_string.at(i);
}

Checking for a Vowel

Use a conditional to see if the characters in the string are equal to any
vowels. Make sure to account for both uppercase and lowercase vowels.

if (ch == 'a' || ch == 'e' || ch == 'i' ||


ch == 'o' || ch == 'u' || ch == 'A' ||
ch == 'E' || ch == 'I' || ch == 'O' ||
ch == 'U') {

Note that characters are wrapped in single quotes ' ', not double quotes in
C++.
Incrementing the Counter

If ch equals any of the vowels, increment the count variable.

count += 1;

Printing the Result

The string may contain no vowels, one vowel, or more than one vowels.
Thus, you’ll need conditionals to output the appropriate responses.

if (count == 0) {
cout << "There are no vowels in the string." << endl;
}
else if (count == 1) {
cout << "There is 1 vowel in the string." << endl;
}
else {
cout << "There are " << count << " vowels in the string." <<
endl;
}

You should see that there are 9 vowels in the string.

Code
string my_string = "The Brown Dog Jumps Over The Lazy Fox";
char ch;
int count = 0;

for (int i = 0; i < my_string.length(); i++) {


ch = my_string.at(i);
if (ch == 'a' || ch == 'e' || ch == 'i' ||
ch == 'o' || ch == 'u' || ch == 'A' ||
ch == 'E' || ch == 'I' || ch == 'O' ||
ch == 'U') {
count += 1;
}
}

if (count == 0) {
cout << "There are no vowels in the string." << endl;
}
else if (count == 1) {
cout << "There is 1 vowel in the string." << endl;
}
else {
cout << "There are " << count << " vowels in the string." <<
endl;
}
Lab Challenge: Vowel Replacement

Replacing Vowels with a *


You are going to write a program that takes a string called my_string and
returns the string but with a * in the place of vowels. Assume that vowels
are upper and lowercase a, e, i, o, u. For example, if my_string =
"Hello", then your program will print "H*ll*".

Some of the code has already been filled out for you. Your task is to
complete the program so that it produces some of the sample output below.
If you accidentally change anything from the original code, you can copy
and paste the code back into the text editor.

#include <iostream>
using namespace std;

int main(int argc, char** argv) {

string my_string = (argv[1]);


char ch;

//add code below this line

//add code above this line

return 0;

Compile and test your code with a few different values

Expected Output
Hll

Expected Output
ppl
Expected Output
Wtrmln!

Requirements

You should not make any changes to the code that already exists. If you
accidentally delete any existing code, you can copy and paste the entire
program from above.
You can use any number of string functions and conditionals to
produce the desired output.
Learning Objectives: Reading
Demonstrate how to open a file using ifstream

Use the get(), getline(), and rdbuf() functions to read a


string stream

Iterate through a file using a while loop

Define the term “token”

Tokenize a string read from a file using a delimiter

Ignore characters in a file with the ignore() function


File Basics

File Basics
This module is all about working with files on a computer. The first step is
to locate the desired file. That means being able to navigate the file system.
The file we are going to use is called practice1.txt. It is located in the text
folder, which is inside the folder called student. So the path to the file is:
student/text/practice1.txt.

File Path

Use a string to represent the file path. This string will be passed to direct
the system to open a file.

string path = "student/text/practice1.txt";

Opening and Closing Files


One of the most common ways to open, close, read, and write files is to use
the ifstream or ofstream data type. The difference between ifstream and
ofstream is that ifstream is used to read data from files whereas ofstream is
used to write to files. Both of these data types can be accessed and utilized
by including #include <fstream> in the header of your code file. Let’s try to
open practice1.txt as specified from above using ifstream.

string path = "student/text/practice1.txt";

ifstream file;
file.open(path);

You’ll see that Command was successfully executed. is returned, which isn’t
very helpful. To know if the file was opened successfully, you can set up
conditions like so:

string path = "student/text/practice1.txt";

ifstream file;
file.open(path);
if (file.is_open()) {
cout << "File successfully opened." << endl;
}
else if (!file.is_open()) {
cout << "File failed to open." << endl;
}

challenge

What happens if you:


Change if (file.is_open()) to if (file)?
Change else if (!file.is_open()) to else if (!file)?
Change the string path to "student/text/practice2.txt"?

Before your program terminates, it is a best practice to close the file. When
a file is opened, it takes up memory that will not free up until the file is
properly closed.
string path = "student/text/practice1.txt"; // setting file path

ifstream file; //create a read-only data stream


file.open(path); //open the file as a stream
if (file) { //check if file exists
cout << "File successfully opened." << endl;
}
else if (!file) { //check if file does not exist
cout << "File failed to open." << endl;
}
file.close(); //close the file

File Error Handling


Back in the “User-Defined Functions” module, you were introduced to the
try, throw, and catch blocks which are used to handle runtime errors that
occur as the program runs. You can apply the same concept to catch errors
when opening files which is the preferred way to handle these errors.

string path = "student/text/practice1.txt";

try { //try these actions


ifstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open."); //throw error
}
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

challenge

What happens if you:


Change the string path to "student/text/practice2.txt"?
info

What is cerr?
When printing error messages, cerr is preferred over cout. cerr is not
bufferred, which means it is not stored in memory to be printed later
on. It just gets printed immediately. Therefore, as a rule of thumb,
important data and variables should be printed with cout while error
messages should be printed with cerr.
Reading a File

Reading a File
Let’s start reading from a file that contains some text. First set the string
path to student/text/readpractice.txt. Then open the file and handle any
opening errors. To read from a file, use the getline() function. The
getline() has at least two parameters; the first is the input stream to read
from and the second is a string to store what is read.

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read; //create string to store what is read into
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
getline(file, read);
cout << read;
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}
important

IMPORTANT
You’ll notice from above that the system printed File successfully
opened and closed. first and then C++ was created by Bjarne
Stroustrup. was printed. This is due to cerr being unbuffered, which
means it gets printed immediately. cout is buffered, so it will store its
content into memory before printing, which explains the delay. This
doesn’t mean that cerr always gets printed first, it just depends on
what on quickly cout stores its content.

To see the content of the file readpractice.txt, click this link here:
readpractice.txt

If you take a look at the content of the file, you’ll see that it has more text
than just C++ was created by Bjarne Stroustrup.. The reason why only
one line of text was printed is because getline() only reads up until a
newline character is reached. To continue to read more lines of text, wrap
getline() inside a while loop.

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read; //create string to store what is read into
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
cout << read;
}
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}
challenge

What happens if you:


Change cout << read; in the code to cout << read << endl;?
Change the entire code to:

string path = "student/text/readpractice.txt";

try {
ifstream file;
char ch; //create string to store what is read into
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (file.get(ch)) {
cout << ch;
}
file.close();
cerr << "File successfully opened and closed." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}

Change cout << ch; in the new code to cout << ch << endl;?

The get() function in the new code works similarly to the getline()
function. However, get() reads character by character instead of by
strings.

Additionally, did you notice that File successfully opened and closed.
was printed at two different locations before and after << endl was added?
This all depends on how quickly cerr and cout work behind the scenes. To
avoid inconsistencies in printing, we’ll avoid printing the success message
moving forward.
Reading a Buffer

The rdbuf() Function


The getline() and get() functions require a variable to store its content. If
all you want to do is to read a file however, then the variable becomes
useful and simply takes up extra memory. When a file is opened, its content
is buffered or stored in memory until it gets closed. During this buffering
stage, you can use the function rdbuf() to read the content of the file
without having to create any variables.

string path = "student/text/readpractice.txt";

try {
ifstream file;
file.open(path); //content of file goes into memory buffer
if (!file) {
throw runtime_error("File failed to open.");
}
cout << file.rdbuf(); //read the buffered content
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

challenge

What happens if you:


Switch the line cout << file.rdbuf(); with file.close()?

If the file is closed, the buffer gets flushed to clear the memory that was
used. So after a file is closed, you will not be able to read the buffered
content anymore.
Delimiters

Delimiters
Delimiters are a predefined character that separates one piece of
information from another. Some common delimiters involve white spaces
(' ') and commas (','). When using getline() previously, we only made
use of two of its parameters. It actually has a third parameter which is
reserved for a delimiter. By default, this delimiter is the newline character
('\n'). Thus the parameters for getline(x, y, z) are:
* The stream source (x).
* The string variable to store what is read (y).
* The delimiter to separate the content of the stream source (z).

Let’s specify the getline() function to use a comma as a delimiter ,.

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
getline(file, read, ','); //specify comma as delimiter
cout << read;
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see file’s content: readpractice.txt

When a delimiter is applied, the system will read only up to that delimiter.
This is why you only see content up through the first comma occurrence. If
you want to continue reading further and get to the other comma
occurrences, you can put the command inside a while loop.
string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) { //specify comma as
delimiter
cout << read;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see file’s content: readpractice.txt

The code above continues to read the stream and separates the content via
the delimiter, ,. This is why there are no commas present in the output.
However, it doesn’t look very clear that the stream has been separated
since the system continues to print the remainder of the stream. You can
add << endl to the output so that the system will print a newline after each
delimiter is reached so that you can see clearer where the content is
separated.
string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) { //specify comma as
delimiter
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see file’s content: readpractice.txt

challenge

What happens if you:


Change the delimiter argument from ',' to a white space ' '?
Change the delimiter again to an 'a'?
Change the delimiter again to a newline '\n'?

Click to see file’s content: readpractice.txt


Tokens

Tokens
When we apply a delimiter to break up a stream or string, the resulting
separated strings are sometimes referred to as tokens. Tokens are useful if
you want to use their data for further analysis later on. For example, you
can store each token as an element in a vector in which you can extract
further information from later on. What do you think the code below does?

The following file contains the first and last names of 5 individuals:
names.txt
string path = "student/text/names.txt";
vector<string> names;
string last_name = "Smith";
int count = 0;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ' ')) {
names.push_back(read);
}
file.close();
for (int i = 0; i < names.size(); i++) {
if (i % 2 == 1) {
if (names.at(i) == last_name) {
count++;
}
}
}
cout << "There are " << count << " people whose last name is
Smith." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}

The code above enables you to do several things:


1. Break the stream into several tokens separated by a white space.
2. Store the tokens into a vector.
3. Iterate through the vector to count how many people have the last name
“Smith”.
4. Print the resulting count.
challenge

What happens if you:


Try to search for a first name such as "Jackie" instead?
Sample Solution

string path = "student/text/names.txt";


vector<string> names;
string first_name = "Jackie"; //change variable to first
name
int count = 0;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ' ')) {
names.push_back(read);
}
file.close();
for (int i = 0; i < names.size(); i++) {
if (i % 2 == 0) { //start checking index 0 and then
every other index
if (names.at(i) == first_name) { //first name found
count++;
}
}
}
cout << "There are " << count << " people whose first
name is Jackie." << endl;
} //change the print statement as needed

catch (exception& e) {
cerr << e.what() << endl;
}

Applying Another Delimiter


If you need to further break down your tokens, you can use a nested loop to
iterate through those tokens to break them down even further. For
example, if your list of names was organized like this:

Jason Seymore
Jackie Simmons
Jennifer Small
Jane Smith
John Smith

Then using the code above will cause issues since it only takes a white
space as a delimiter, not a newline. To include both the newline and white
space as delimiters, you can use a stringstream data type (#include
<sstream>) to create another string stream off of the string variable read.
The first getline() function will separate the stream using a newline as the
delimiter and the second getline() will use a white space as a delimiter.
string path = "student/text/names2.txt";
vector<string> names;
string last_name = "Smith";
int count = 0;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) { //newline delimiter
stringstream ss(read); //create a string stream of read
while (getline(ss, read, ' ')) { //white space delimiter
names.push_back(read);
}
}
file.close();
for (int i = 0; i < names.size(); i++) {
if (i % 2 == 1) {
if (names.at(i) == last_name) {
count++;
}
}
}
cout << "There are " << count << " people whose last name is
Smith." << endl;
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click to see files’ content: names2.txt and names.txt

challenge

What happens if you:


Change the string path from "student/text/names2.txt" to
"student/text/names.txt"?

Notice how you get the same result regardless of how your names are
organized in the text file.
Ignore Function

The Ignore Function


The ignore function takes an integer as a parameter, and causes C++ to go
to a specific character in the text file. The integer is the index for the text
file. So ignore(0) is the first character of the file, ignore(1) is the second
character, etc. The code below prints out the entire text file.

Click to see file’s content : readpractice.txt

string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Now compare the output above with the output from the code below. C++
will ignore the first 29 characters and start reading only from the character
at position 30.
string path = "student/text/readpractice.txt";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.ignore(30); //ignore all chars before index 30
while (getline(file, read)) {
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

challenge

Try these variations:


Change the ignore argument to 40: file.ignore(40);
Change the ignore argument to 400: file.ignore(400);

Why do I see Command was successfully executed.?


The text file only has 242 characters total, which include white spaces
and newlines. Ignoring all characters before index 400 is like ignoring
the entire file. Nothing gets read or printed which is why the system
returned Command was successfully executed..
Learning Objectives: Writing
Demonstrate how to open a file and write to it using
ofstream

Explain what happens when you write to a file that does


not exist

Demonstrate how to write multiline strings to a file

Differentiate between input, output, and append modes


Writing to a File

Writing to a File
When writing to a file, you’ll want to use ofstream instead of ifstream. Like
before, create your string path, open the file, and check for whether it can
be opened successfully.

string path = "student/text/practice1.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

If the file is successfully opened, you can start writing to the file using the
insertion operator << followed by what you want to write in double quotes
"". Remember to close the file, and if you want, you can print a message at
the end telling the user that that the file was successfully written to.
string path = "student/text/practice1.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file << "Hello there";
file.close();
cerr << "Finished writing to file.";
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Click on the link to open the file and see what was wrttien: Open
practice1.txt

challenge

Try these variations:


Open the practice1.txt file after each change to see what gets written.
* Change "Hello there" to "Goodbye".
* Change "Goodbye" in your current code to "".
* Open student in the sidebar on the left. Open the text folder and
right-click on practice1.txt. Select Delete... and YES to delete the file
and then run the program again.

Why is there no error message?


If you tell C++ to create an ofstream file, it will automatically create
that file if one does not exist. Or it will overwrite the existing file with a
new one. This is why you do not see an error message. You will only see
an error message if for some reason the system is not able to create the
file at all.

Open practice1.txt

Reading a Written File


If you want to read from the file after it was written to, you can create an
ifstream to read from the file.
string path = "student/text/practice1.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file << "Hello there";
file.close();

ifstream stream;
string read;
stream.open(path);
while (getline(stream, read)) {
cout << read << endl;
}
stream.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

challenge

What happens if you:


Change "Hello there" to "Hi!".
Add file << " My name is AI." << endl; to the line after file <<
"Hi!";?
Multiline Strings

Multiline Strings
In addition to being able to write and output string literals (e.g. file <<
"Hi!";), we can also write and output the content of variables (e.g. file <<
var;). Let’s tweak the code from the previous page to write multiple
messages to a text file called practice2.txt. We’ll create three string
variables, text1, text2, and text3. The first message will go into a string
variable text1, the second will go into text2, and the third will go into
text3.

string path = "student/text/practice2.txt";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
string text1 = "Hello, ";
string text2 = "your balance is: ";
string text3 = "12.34";
file << text1 + text2 + text3;
file.close();

ifstream stream;
string read;
stream.open(path);
while (getline(stream, read)) {
cout << read << endl;
}
stream.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Open practice2.txt
challenge

What happens if you:


Change string text3 = "12.34"; to double text3 = 12.34;?
Change file << text1 + text2 + text3; to file << text1 + text2
<< text3;?
Split the code file << text1 + text2 << text3; into two lines:

file << text1 + text2 << endl;


file << text3;

Change file << text1 + text2 << endl; to file << text1 + text2
<< '\n';?
Change file << text1 + text2 << '\n'; to file << "Hello, your
balance is:\n12.34"; and remove file << text3;?

Open practice2.txt

Notice how you can also write the content of other types of data (double,
int, etc.) to a file. You are not restricted to just strings. Also, there are
multiple ways to write the same kind of content to a file.
Appending to a File

Appending to a File
You may have noticed that every time a file is opened using an ofstream
object, a new file is always created, even if one already exists (the system
just overwrites the existing file). If you want to add to an existing file, you
have to tell C++ to open the file in append mode. Let’s look at the code
below and TRY IT.

string path = "student/text/practice3.txt";

try {
ofstream file;
file.open(path, ios::app); //open file in append mode
if (!file) {
throw runtime_error("File failed to open.");
}
string text = "Adding to the file.";
file << text;
file.close();

ifstream stream;
string read;
stream.open(path);
while (getline(stream, read)) {
cout << read << endl;
}
stream.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Open practice3.txt

Since there is no practice3.txt file at the start of the program, C++ will
create one. However, try running the code again and see what happens.

Open practice3.txt
You’ll notice that the output Adding to the file. shows up twice in the file.
This happens because we have included the tag ios::app as a second
parameter when we opened up the file practice3.txt. By default, an
ofstream object has the flag ios::out as a second parameter, which causes
the file to always get overwritten. By changing the parameter to ios::app,
we’re telling the system to add to the file instead of overwriting it.

challenge

What happens if you:


Change ios::app in the code to ios::out?
Change ios::out to ios::in?
Change file << text; to file << text << text;?
Change file << text << text; to file << "Hello";?
Change ios::in back to ios::app?

Open practice3.txt

If you follow through the challenges above, you’ll notice that when the flag
is set to input mode ios::in, the system will overwrite the content without
creating a new file or overwriting the old one. On the other hand, ios::app
will add to the end of the existing content. Lastly, ios::out creates a
completely new file and writes to it.
Learning Objectives: CSV
Define CSV

Read data from a CSV file

Iterate over a CSV file

Print data from a CSV file with formatting

Write data to a CSV file


CSV Files

CSV Files
C++ can work with files besides just text files. Comma Separated Value (CSV)
files are an example of a commonly used file format for storing data. CSV
files are similar to a spreadsheet in that data is stored in rows and columns.
Each row of data is on its own line in the file, and commas are used to
indicate a new column. Here is an example of a CSV file.

Month Python CSV

You can read a CSV file in the same way you read a text file. First create an
ifstream object and then open the CSV file using it.

string path = "student/csv/monty_python_movies.csv";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) {
cout << read + ' ';
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
To iterate through the CSV file, we use while (getline(file, read, ',')).
Since CSV files contain commas that separate information, we set the
delimiter to ','. Then we print the content by using cout << read + ' '.
We add a space to separate the tokens from each other since it is not
apparent that the information is tokenized from using just cout << read;.

challenge

Try this variation:


Change cout << read + ' '; to cout << read << endl;?

By using cout << read << endl; you can clearly see each token line by line.
Depending on your preference, you can choose to arrange the tokens in a
variety of different formats.

Ignoring the Header


The first row of a CSV file is helpful because the header values provide
context for the data. However, the first row is not useful if you want to
know how many rows of data there are, or to calculate the avg value, etc.
Here, you can also use the ignore() function to skip a specific number of
characters.

string path = "student/csv/monty_python_movies.csv";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.ignore(19); //Ignore the first 19 characters from index
0-18
while (getline(file, read, ',')) {
cout << read << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
challenge

Try this variation:


Change file.ignore(19); to file.ignore(53);?
Change file.ignore(53); to file.ignore(500);?
Change file.ignore(500); to file.ignore(500, '\n');?
Add another file.ignore(500, '\n'); below the first
file.ignore(500, '\n');?

The file.ignore(500, '\n'); command tells the system to skip the first
500 characters or up through the newline character \n. Since there are
fewer than 500 characters, the system will skip everything up through the
first occurrence of the newline. You can add additional ignore commands
to ignore more lines of data if needed.
Printing CSV Data

Printing CSV Data


Iterating over the CSV file and printing each line does not produce visually
pleasing output. The code below produces three columns of data, but there
is no consistency in the spacing between columns. When printed, the data
looks very disorganized and difficult to read.

string path = "student/csv/homeruns.csv";

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, ',')) {
cout << read + " ";
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

To better organize our CSV data, we can store the data into a vector and
then format and print elements in a way that looks more organized.
string path = "student/csv/homeruns.csv";
vector<string> data;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
data.push_back(read);
}
}
file.close();
for (int i = 0; i < data.size(); i++) {
if (i % 3 == 0) {
cout << setw(20) << left << data.at(i);
}
else if (i % 3 == 1) {
cout << setw(15) << left << data.at(i);
}
else {
cout << data.at(i) << endl;
}
}
}

catch (exception& e) {
cerr << e.what() << endl;
}

To organize our data, we use conditionals to split our elements into three
columns. if (i % 3 == 0) refers to the elements in the first column, else
if (i % 3 == 1) refers to the second column, and else refers to the third.
We use the setw() function to provide padding for our elements. For
example, setw(20) means that the system will reserve 20 characters for the
elements. If the element does not take up 20 characters, then white spaces
will occupy those spaces. To use setw(), you’ll need #include <iomanip> in
the header of your file. The left tag forces the element to be aligned to the
left side.
challenge

Try this variation:


Change setw(20) to setw(16)?
Change setw(15) to setw(10)?
Delete the second left tag?
Delete the first left tag?
Note
By default, standard streams are set to right. This is why deleting
all of the left tags will effectively align the streams back to the
right side. Additionally, you only have to set the left tag once for
all streams that follow to align left as well.

Notice how the last column Active Player is not formatted and is therefore
unaffected by the changes.

important

IMPORTANT
The order or placement of where you use left and setw() can affect all
streams that follow. So it’s important to keep track of the changes that
take place as you print. For example outputting
Writing to CSV Files

Writing to a CSV File


Writing to a CSV files is similar to writing to a text file. First create an
ofstream object to open the CSV file. Then you can write to the CSV file
using the insertion operator <<. To read the CSV file, you can use the same
syntax that was previously shown.

string path = "student/csv/writepractice.csv";

try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file << "Greeting,Language" << endl;
file << "Hello,English" << endl;
file << "Bonjour,French" << endl;
file << "Hola,Spanish";
file.close();

ifstream file2;
string read;
file2.open(path);
while (getline(file2, read, ',')) {
cout << read + ' ';
}
file2.close();
}

catch (exception& e) { //catch error


cerr << e.what() << endl;
}

Click to open CSV file: writepractice.csv

To organize the CSV data, you can add each token into a vector and then
use conditionals to format and print the data like before.
string path = "student/csv/writepractice.csv";
vector<string> data;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
data.push_back(read);
}
}
file.close();
for (int i = 0; i < data.size(); i++) {
if (i % 2 == 0) {
cout << setw(15) << left << data.at(i);
}
else {
cout << data.at(i) << endl;
}
}
}

catch (exception& e) {
cerr << e.what() << endl;
}
Lab 1

Lab 1
As you read a text file, you go line by line until you reach the end of the file.
What happens if you want to go back to a specific line of text? A common
practice that comes with reading text from a file is to store that information
into something like a vector. This way you can easily reference any data
obtained from the file.

Before reading the file, create the path variable with the file path, and
instantiate the string vector text.

string path = "student/labs/fileslab1.txt";


vector<string> text;

Use try, throw and catch blocks to handle input/output exceptions. In the
try portion, create an ifstream object to read through the file and store its
content into a string variable. While reading, add each line to the vector
text. Print any errors in the catch portion. You can optionally print a
message that the file has successfully been read, but that is not required.

string path = "student/labs/fileslab1.txt";


vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
text.push_back(read);
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
The content of the text file now resides in the vector variable text.
However, the code above only adds text from the file into the vector. To
print what was stored in the vector, use a loop to iterate the vector’s
elements first followed by the cout command.

string path = "student/labs/fileslab1.txt";


vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
text.push_back(read);
}
for (int i = 0; i < text.size(); i++) {
cout << text.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

You should see a passage from Bram Stoker’s Dracula. You’ll notice,
however, that the output is just a collection of text grouped together. In
fact, if you were to print the first element in the vector, you will get the
same result. The entire file was read and stored as the first element in the
vector. This occurs because the default delimiter is a newline and there is
only 1 occurrence of a newline at the end of the file.

Let’s change the delimiter into a period . so that the text will be tokenized
into sentences. Each token will represent one sentence from the passage.
string path = "student/labs/fileslab1.txt";
vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) { //set delimiter as a period
text.push_back(read);
}
for (int i = 0; i < text.size(); i++) {
cout << text.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

The passage is tokenized using a period . as a delimiter. When the


delimiter is specified, the system extracts the period from the text, this is
why you do not see the periods in the output. To put the periods back into
the vector, simply include + '.' in the push_back() statement.
string path = "student/labs/fileslab1.txt";
vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) {
text.push_back(read + '.'); //add period to end
}
for (int i = 0; i < text.size(); i++) {
cout << text.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Your vector now includes 4 elements, each representing a sentence from


the passage extracted from the file fileslab1.txt. To bring your focus to a
particular sentence, you can use the at() function and specify the position
of the sentence you are interested in.
string path = "student/labs/fileslab1.txt";
vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) {
text.push_back(read + '.');
}
cout << text.at(1); //print the second element/sentence
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

To erase the first leading white space, you can use text.at(1).erase(0, 1).
This will take the system to the first position, index 0, and erase just 1
character in that string.

string path = "student/labs/fileslab1.txt";


vector<string> text;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read, '.')) {
text.push_back(read + '.');
}
cout << text.at(1).erase(0, 1) << endl; //erase the first
string char
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}
Lab 2

Lab 2
This lab uses a comma delimited CSV file fileslab2.csv, which contains
integers. There are three columns and four rows. The program below will
print the sum for each row in the CSV. This is what the file currently looks
like:

1,4,5
18,34,99
0,12,51
37,29,61

We’ll start with directing the path to the file, creating a vector nums to store
the data for later, creating an ifstream and string to read and hold the
content of the file temporarily, and using try, throw and catch blocks to
handle any issues when opening the file.

string path = "student/labs/fileslab2.csv";


vector<string> nums;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

After, use the getline() function to iterate through the file and store its
content as tokens in the vector. Note that you will need to go through the
file twice and include a stringstream object to further help tokenize the
data. Try running the code below to see what’s currently stored.
string path = "student/labs/fileslab2.csv";
vector<string> nums;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
nums.push_back(read);
}
}
for (int i = 0; i < nums.size(); i++) {
cout << nums.at(i) << endl;
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

You should see a list of numbers after the code runs. Though what you see
are numbers, they are currently strings which means we cannot do
calculations on them directly. We must convert them into integers first
using stoi(). Additionally, the data is stored in a vector which is one
dimensional but we want to calculate totals for multiple rows. To achieve,
we’ll use a double nested for loop to iterate through the vector in chunks of
three elements which will allow us to calculate the totals of each row.
string path = "student/labs/fileslab2.csv";
vector<string> nums;

try {
ifstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
while (getline(file, read)) {
stringstream ss(read);
while (getline(ss, read, ',')) {
nums.push_back(read);
}
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

for (int i = 0; i < nums.size(); i+=3) {


int total = 0;
for (int j = 0; j < 3; j++) {
total += stoi(nums.at(i + j));
}
cout << "Total: " << total << endl;
}

Your program should print the following output:

Total: 10
Total: 151
Total: 63
Total: 127
Lab 3

Lab 3
The goal of this lab is to rely on user input for data. We are going to
continuously ask the user to enter the name of a superhero followed the
name of their power. If the user enters lowercase q, the system will stop
collecting data and write all of the data collected to the CSV file
superheroes.csv.

First let’s create our string path, ofstream object, read string, and exception
blocks like usual.

string path = "student/labs/superheroes.csv";

try {
ofstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Next, we need to create variables for our user input. Additionally, we also
need to continuously ask the user for output until they enter q. After q is
detected, the information entered will be written to our CSV file.
string path = "student/labs/superheroes.csv";
string name;
string power;

try {
ofstream file;
string read;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}

while (true) {
cout << "Please enter a superhero name (or enter q to quit):
";
cin >> name;
if (name == "q") {
break;
}
cout << "Please enter a superhero power (or enter q to
quit): ";
cin >> power;
if (power == "q") {
break;
}
file << name << ',' << power;
}

file.close();
}

catch (exception& e) {
cerr << e.what() << endl;
}

Click the TRY IT button to enter information into the terminal. Enter q to
stop the data collection and write to to the CSV file. Click on the CSV file link
below to see everything that was entered.

Open superheroes.csv
Lab Challenge

Lab Challenge
Write a program that reads a text file . This file is stored in the variable
path.

DO NOT alter this line of code in the program!

////////// DO NOT EDIT! //////////


string path = argv[1]; //
//////////////////////////////////

The file contains several instances of the word Burma. Replace each instance
of Burma with Myanmar, and print the results of this transformation. The final
output of your program should be:

Myanmar is a country in Southeast Asia.


The capital of Myanmar is Naypyidaw.
Its population is about 54 million people.
Myanmar is a former British colony.

Hint
You can use the FindAndReplace() function to replace all instances of Burma
with Myanmar. Note that you will need to store the content of the file into a
string in order to use this function.
Learning Objectives: Function
Basics
Demonstrate how to define a function

Differentiate between the function header and the


function body

Identify the importance of the order of function


definitions

Identify the purpose of C++ code documentation


Function Definition

Function Syntax
You have seen and used built-in functions like the length function
(my_string.length()). This unit deals with user-defined functions.
Functions are composed of two parts, the header and the body.

.guides/img/FunctionFull

The function header may contain several keywords to determine the


function type. Next is the name of the function. “Ordinarily, functions
should start with a capital letter and have a capital letter for each new
word.”
(https://google.github.io/styleguide/cppguide.html#Function_Names). Some
examples include: GreetTwice, AddThree, FindArea, etc. Parentheses are
required but the parameter(s) within them are not. Any command(s)
associated with the function should be indented as a best practice and
enclosed within curly braces {}. This command(s) comprises the body of
the function.

Function Header

.guides/img/FunctionHeader
The function header usually contains a few key labels:
* void - Determines whether there is a return value or not for the function.
If the function has no return value, use void. If the function returns an
integer, use int, etc.
* GreetTwice - This is an example of a function name. See above for naming
conventions.
* () - Parentheses are required for all functions. Any parameters that the
function takes in will go into the parentheses but they are optional.

Function Body

.guides/img/FunctionBody

The function body is the list of actions the function performs. All of the
code for the function body should be enclosed within curly braces {} and
indented as a best practice to show association. This convention is similar
to how conditionals and loops are written.
Function Calls

Calling a Function
Copy the entire code below into the text editor to your left. Then click the
TRY IT button to see what happens.

#include <iostream>
using namespace std;

void GreetTwice() {
cout << "Hello" << endl;
cout << "Hello" << endl;
}

You’ll notice that an error is produced. This happens because when


running C++ programs, a main function is required. Let’s go ahead and add
int main() to the code like so.

#include <iostream>
using namespace std;

void GreetTwice() {
cout << "Hello" << endl;
cout << "Hello" << endl;
}

int main() {

Nothing is outputted when the program is executed. This happens because


creating a function alone does not cause C++ to run it. You have to explicitly
call the function if you want it to run. Functions are usually called within
the main function. To call a function, simply start with its name, provide any
parameters if needed, and end with a semicolon.
#include <iostream>
using namespace std;

void GreetTwice() {
cout << "Hello" << endl;
cout << "Hello" << endl;
}

int main() {
GreetTwice();
}

challenge

What happens if you:


Call GreetTwice again by adding another GreetTwice(); to the
main() function?
Modify GreetTwice by adding the line cout << "Goodbye" << endl;
underneath the second cout << "Hello" << endl;?
Add the command return 0 as the last line in the main() function?

important

IMPORTANT
You may have noticed that adding return 0 to main() in the code above
doesn’t really cause any changes to the program. In older versions of
C++, the command return 0 was required because the main() function
has a return type of int. This means that the function expects some
integer value to be returned at the end of the function. return 0 is
another way for the program to denote that the function has
successfully completed.

Newer versions of C++ can run int main() without return 0, however,
it is still a best practice to include it. Additionally, you should not
change the return type of main() to anything other than int. This is a
standard in C++ and should remain so.

Order of Function Definitions


The order of function definitions is important in C++. If the code is changed
to the following, what do you think will be outputted?

#include <iostream>
using namespace std;

void GreetTwice() {
cout << "Goodbye" << endl;
cout << "Hello" << endl;
cout << "Hello" << endl;
}

int main() {
GreetTwice();
GreetTwice();
return 0;
}

Like how a regular C++ program runs, the function is executed line by line
from top to bottom. Thus, the order of statements within the function will
determine what actions are performed first, second, etc.

Order of Different Functions


The order of the functions themselves also matter. What happens if you
swap the position of main() with GreetTwice() and vice versa?

#include <iostream>
using namespace std;

int main() {
GreetTwice();
GreetTwice();
return 0;
}

void GreetTwice() {
cout << "Goodbye" << endl;
cout << "Hello" << endl;
cout << "Hello" << endl;
}

You will encounter an error such as GreetTwice was not declared in this
scope. Like how function definitions are read line by line from top to
bottom, functions are also read the same way. When the program gets to
the first GreetTwice(); within main(), it doesn’t know what to do because
the function has not been declared yet. Therefore, whenever you call a
function, make sure that you have already declared and defined it. Think of
a function as a vocabulary word, you would not use a vocabulary word that
you do not know the definition of.
Documentation

C++ Code Documentation


Including C++ code documentation prior to function definitions is standard.
Doing so enables users to gain clarity on the purpose of the function, any
parameters that are used, and what the function returns. Users can also see
who wrote the function as well as what version the function is on. There
are several ways to document C++ code, however the style that we will be
using for this module models that of Java’s (also known as Javadoc). Here is
an example, also present within the text editor to your left:

/**
* This is an example of C++ documentation
*
* @author FirstName LastName
* @version 1.0
*/
#include <iostream>
using namespace std;

/**
* This function greets the user twice
*
* @param specify parameters if any
* @return specify return value if any
*/
void GreetTwice() {
cout << "Hello" << endl;
cout << "Hello" << endl;
}

int main() {
GreetTwice();
return 0;
}

The C++ code documentation does not affect the output of the code.
However, it provides more clarity to how the function is used. Generally
speaking, the documentation for authors and program version goes at the
start of the program while the documentation for parameters and return
value goes directly before the declared function. Note that documentation
for the main() function is not required.

Doxygen Tool
There is an online tool called Doxygen that can help generate C++ code
documentation. For more information, you may visit the Doxygen website
at this link: Doxygen. However, for the purposes of this module, we will
only focus on self-created documentation. In particular, we will be using
mostly @param for parameters and @return for return values to document
our functions.
Learning Objectives: Parameters
Demonstrate how to define a function with parameters

Identify which value is assigned to each parameter

Catch exceptions with a try, throw, and catch

Define functions with the same name but different


parameters

Demonstrate how to declare a function with an array


and vector as a parameter
Passing Parameters

Parameters
If a function contains parameters within its definition, they are required to
be present when the function is called. In the example below, the function,
Add(), adds two integer parameters together. Parameters are the types or
values located in between the parentheses. Multiple parameters are
separated by commas.

.guides/img/Parameters1

Copy and paste the following function into the text editor to your left
between the lines //add function definitions below this line and //add
function definitions above this line. DO NOT modify main() yet, or the
code will not print correctly!

/**
* This function adds two integers together
*
* @param num1 The first integer
* @param num2 The second integer
*/
void Add(int num1, int num2) {
cout << num1 + num2 << endl;
}
challenge

What happens if you:


Change the function call in main() to Add(5, "seven");?
Change the function call to Add(); without any parameters?
Change the function call to Add(5, 10, 15);?
Change the entire function to…

void Add(int num1, int num2, int num3) {


cout << num1 + num2 + num3 << endl;
}

important

IMPORTANT
The number of arguments within main() should match the number
of parameters specified in the function. If there are three
parameters, then there should be three arguments as well.
The argument type should also match the parameter type. If the
function requires three integers, then the arguments should also
consist of three integers. You cannot provide a string argument for
an integer parameter, etc.

Order of Parameters

.guides/img/Parameters2
Much like how C++ programs run code from left to right and then top to
bottom, parameters are also read the same way. Because of this, the order
of parameters is important. The first argument in the function call will be
matched with the first parameter in the function header, the second
argument from the function call will be the second parameter in the
function header, etc. Copy the entire code below into the text editor and
then click TRY IT. What do you predict the output will be?

#include <iostream>
using namespace std;

/**
* This function adds the first two integers together,
* then subtracts the third integer
*
* @param num1 The first integer
* @param num2 The second integer
* @param num3 The third integer
*/
void AddSub(int num1, int num2, int num3) {
cout << num1 + num2 - num3 << endl;
}

int main() {
AddSub(5, 10, 15);
return 0;
}

challenge

What happens if you:


Change the function call in main() to AddSub(10, 15, 5);?
Change the function call in main() to AddSub(15, 5, 10);?
Change the function call in main() to AddSub(10 + 5, 20 / 4, 5 *
2);?
Checking Parameters

Checking Parameter Usage


Copy and paste the code below into the text editor and then TRY IT.

/**
* This function divides one integer by the other
*
* @param num1 The first integer
* @param num2 The second integer
*/
void Divide(int num1, int num2) {
cout << num1 / num2 << endl;
}

int main() {
Divide(5, 0);
return 0;
}

You’ll notice that the code produces an exception. An exception occurs


when an operation cannot be successfully completed because a rule is
broken. For example, dividing by 0 results in an undefined answer. Thus
when you try to divide 5 by 0, you get an exception as a response. Not all
exception messages are created equal. Some are more clear than others.
However, you may choose to clearly define an exception by using a try,
throw, and catch.

.guides/img/TryCatchException
/**
* This function divides one integer by the other
*
* @param num1 The first integer
* @param num2 The second integer
*/
void Divide(int num1, int num2) {
try {
if (num2 == 0) {
throw runtime_error("Cannot divide by zero.");
}
else {
cout << num1 / num2 << endl;
}
}
catch (runtime_error& e) {
cout << e.what() << endl;
}
}

int main() {
Divide(5, 0);
return 0;
}

challenge

What happens if you:


Change the function call to Divide(5, 2);?
Change the function call to Divide(0, 2);?
Change the function call to Divide(14.5, 2);?
Change the function call to Divide(14.5, "2");?
important

IMPORTANT
It’s important to note that when arguments are passed as parameters,
C++ tries to implicitly cast the arguments as the specified parameter
type(s) first. In the example above, both 14.5 and 2 get cast as ints.
Thus, 14.5 loses its trailing decimal places and becomes 14. On the
other hand, the string "2" cannot be implicitly cast as an int causing
the system to fail to compile. Note that you can only catch C++
exceptions, not compilation errors.

runtime_error() is one example of an exception that can be used to


produce a specified error message. e is the variable name for which
you are calling the exception by. In C++, exceptions are caught by
reference, not value. Thus, runtime_error& e is preferred over
runtime_error e.

For a list of other exceptions, visit: C++ Exceptions.


Parameter Types

Function with Different Parameters


In C++, you are allowed to define functions with the same name as long as
the parameters are different in quantity or type. Copy the code below and
TRY IT.

/**
* This function adds two integers together
*
* @param num1 The first integer
* @param num2 The second integer
*/
void Add(int num1, int num2) {
cout << num1 + num2 << endl;
}

/**
* This function adds three integers together
*
* @param num1 The first integer
* @param num2 The second integer
* @param num3 The third integer
*/
void Add(int num1, int num2, int num3) {
cout << num1 + num2 + num3 << endl;
}

int main() {
Add(3, 14);
return 0;
}
challenge

What happens if you:


Change the function call to Add(3, 14, 9);?
Change the function call to Add(3, 14, 9, 2);?

The two Add() functions above differ in the number of parameters they
have. Here is an example of two functions with the same name but
different parameter types.

/**
* This function adds two integers together
*
* @param num1 The first integer
* @param num2 The second integer
*/
void Add(int num1, int num2) {
cout << num1 + num2 << endl;
}

/**
* This function prints an integer followed
* by a string
*
* @param num1 The integer
* @param num2 The string
*/
void Add(int num1, string num2) {
cout << num1 << num2 << endl;
}

int main() {
Add(3, 14);
return 0;
}
challenge

What happens if you:


Change the function call to Add(3, "14");?
Change the function call to Add("14", 3);?
Alternative Parameters

Alternative Parameter Types


Function parameters do not necessarily need to belong to one of the four
commonly used data types (int, string, double, bool). In fact, parameters
can be arrays/vectors and even objects. For now, we will not focus on
objects, which will be covered in a future module.

/**
* This function prints all values of an array
*
* @param array A string array
*/
void PrintArray(string array[], int size) {
for (int i = 0; i < size; i++) {
cout << array[i] << endl;
}
}

int main() {
string names[] = {"Alan", "Bob", "Carol"};
int len = sizeof(names) / sizeof(names[0]);
PrintArray(names, len);
return 0;
}

challenge

What happens if you:


Change string names[] = {"Alan", "Bob", "Carol"}; to string
names[3];?
Add names[0] = "Alan"; to the line below string names[3];?
Change the first function parameter of string array[] to string*
array?

Why Doesn’t the Code Below Work?


/**
* This function prints all values of an array
*
* @param array A string array
*/
void PrintArray(string array[]) {
for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++) {
cout << array[i] << endl;
}
}

int main() {
string names[] = {"Alan", "Bob", "Carol"};
PrintArray(names);
return 0;
}

important

IMPORTANT
When an array is passed as a function argument in C++, the system
treats the array as a pointer that points to the first element within the
array. Thus, the parameter string array[] is the same as string*
array. Due to this, knowledge of the size of the array is lost. This is why
it is a good practice to include an integer parameter for functions
involving arrays so that the size can be calculated and stored before
those functions are called.
Learning Objectives: Variable
Scope
Differentiate between global and local scope

Explain what the keyword “const” does


Local Scope

Local Scope
Take a look at the code below. The first function declares the variable
my_var and then prints it. The second function also prints my_var. What do
you think the output will be?

void MyFunction1() {
string my_var = "Hello";
cout << my_var << endl;
}

void MyFunction2() {
cout << my_var << endl;
}

int main() {
MyFunction1();
MyFunction2();
return 0;
}

C++ returns an error such as error: ‘my_var’ was not declared in this
scope at the line containing cout << my_var << endl; within the second
function. This happens because variables declared inside a function have
local scope. Variables with local scope can only be used within that
function. Outside of that function, those local variables cannot be accessed.
In the image below, the light blue box represents the scope of my_var. Since
MyFunction2 (denoted in a light red box) is outside the scope of my_var, an
error occurs.
.guides/img/LocalScope

challenge

What happens if you:


Change MyFunction2 to look like this:

void MyFunction2() {
string my_var2 = "Hello";
cout << my_var2 << endl;
}

More Local Scope


Each function has its own local scope. That means you can declare two
variables with the same name as long as they are in separate functions. The
blue my_var exists only in the light blue box, and the red my_var exists only
in the light red box. The boundaries of local scope keep C++ from
overwriting the value of the first variable with the contents of the second.
.guides/img/LocalScope2

void MyFunction1() {
string my_var = "Hello";
cout << my_var << endl;
}

void MyFunction2() {
string my_var = "Bonjour";
cout << my_var << endl;
}

int main() {
MyFunction1();
MyFunction2();
return 0;
}
challenge

What happens if you:


Declare MyFunction3() as:

void MyFunction3() {
string my_var = "Hola";
cout << my_var << endl;
}

and call it by including MyFunction3(); within the main() function.


Global Scope

Global Scope - Referencing Variables


When a variable is declared inside a function, it has local scope. When a
variable is declared outside of all existing functions, it has global scope.
Since global variables are declared outside of functions, they can be
referenced inside any function. Look at the image below. The yellow block
holds everything within the program including the variable greeting. This
enables all functions within the program to access that variable since it is
considered to be global. Copy and paste the code below and then click TRY
IT.

.guides/img/GlobalScope

string greeting = "Hello"; //global variable

void SayHello() {
cout << greeting << endl; //can access global variable
greeting
}

int main() {
SayHello();
return 0;
}

Global Scope - Modifying Variables


Once a global variable becomes available, a function can modify the
content of that variable as needed.

string greeting = "Hello";

void SayHello() {
greeting = "Bonjour";
cout << greeting << endl;
}

int main() {
SayHello();
return 0;
}

challenge

What happens if you:


Change greeting = "Bonjour"; within SayHello() to greeting =
"Hola";?
Change the entire program to:

string greeting = "Hello";

void SayHello1() {
greeting = "Bonjour";
cout << greeting << endl;
}

void SayHello2() {
cout << greeting << endl;
}

int main() {
SayHello1();
SayHello2();
return 0;
}

Notice how in the code above the functions SayHello1() and SayHello2()
end up printing the same output. The result of greeting within SayHello2()
is affected by the modification of greeting within SayHello1().
Global vs. Local Scope

Global vs. Local Scope


If a variable is declared and initialized both locally and globally, that
variable will retain its content depending on how it is used. In the example
below, my_var is declared and initialized globally as global scope and
locally as local scope. Since the variable has differing scopes, it retains its
value when called or printed.

string my_var = "global scope";

void PrintScope() {
string my_var = "local scope";
cout << my_var << endl;
}

int main() {
PrintScope();
cout << my_var << endl;
}

The exception to this rule is when a function modifies a global variable. In


such a case, the content of the global variable is changed.

string my_var = "global scope";

void PrintScope() {
my_var = "local scope";
cout << my_var <<endl;
}

int main() {
PrintScope();
cout << my_var << endl;
}
challenge

What happens if you:


Change the code to:

string my_var = "global scope";

void PrintScope(string my_var) {


my_var = "local scope";
cout << my_var << endl;
}

int main() {
PrintScope(my_var);
cout << my_var << endl;
}

When a global variable is also a function parameter, it is considered to be


the same as if the function declared and initialized its own local variable.
In this case, the variable has both a local and global scope and will retain
its value depending on its scope.

The “const” Keyword


If you want a global variable to remain unchanged throughout the
program, you can declare the variable as const. const variables are also
referred to as constants. Constants never change and are “named with a
leading ‘k’ followed by mixed case. Underscores can be used as separators
in the rare cases where capitalization cannot be used for separation.”
Source: Google

Another common way to label constants is to use names in all uppercase


with words separated by an underscore (_). For example: MY_CONSTANT.
const string kMyConstant = "I NEVER CHANGE";

void PrintScope() {
kMyConstant = "I CAN'T CHANGE";
cout << kMyConstant << endl;
}

int main() {
PrintScope();
cout << kMyConstant << endl;
}

challenge

What happens if you:


Remove the keyword const from the code?
Learning Objectives: Returning
Values
Use the return keyword to return a value

Identify the return value of the print statement

Demonstrate the ability to return several different data


types

Create and apply helper functions


Returning Values

The Return Keyword


Instead of just printing data, functions can also return data. Think of the
sizeof() and length() functions. They help return the size or length (in
integer) of an array and string respectively. So the return value of these
functions is of type int. Both sizeof() and length() do not print anything
to the screen, they just return a number. From here on out, user-defined
functions will avoid just printing to the screen. Instead, they will return a
value. To return a value, simply use the return keyword.

/**
* This function adds 5 to an integer
*
* @param num An integer
* @return The integer added to 5
*/
int AddFive(int num) {
return num + 5;
}

int main() {
AddFive(10);
return 0;
}

You’ll notice the program no longer prints anything to the screen, which is
the cause for the message, Command was successfully executed.. This
happens because the function only adds 5 to whatever parameter is passed
to the function and then returns it internally. To see the result, explicitly tell
C++ to print the return value of the function to the screen.
/**
* This function adds adds 5 to an integer
*
* @param num An integer
* @return The integer added to 5
*/
int AddFive(int num) {
return num + 5;
}

int main() {
int newNum = AddFive(10);
cout << newNum << endl;
return 0;
}

challenge

What happens if you:


Remove all lines of code within main() and replace them with just
cout << AddFive(10) << endl; and then return 0;?

Returning Values
Functions can return any value in C++ — ints, doubles, strings, vectors, etc.
/**
* This function adds two integers together
*
* @param x The first integer
* @param y The second integer
* @return x added to y
*/
int ReturnInt(int x, int y) { //int function
return(x + y);
}

/**
* This function adds two doubles together
*
* @param x The first double
* @param y The second double
* @return x added to y
*/
double ReturnDouble(double x, double y) { //double function
return(x + y);
}

/**
* This function adds two strings together
*
* @param x The first string
* @param y The second string
* @return x added to y
*/
string ReturnString(string x, string y) { //string function
return(x + y);
}

int main() { //int function


cout << ReturnInt(1, 2) <<endl;
cout << ReturnDouble(1, 2) <<endl;
cout << ReturnString("1", "2") << endl;
return 0;
}

challenge

Can you write a function that returns a


vector?
If you want to return a vector, one possible approach is to have a
vector be passed as a parameter. You can then modify the vector in
some way, and then return it to the system.
Sample Code

The code below takes a vector of numbers as a parameter for the


function MultiplyFive(). The function creates a new empty vector,
multiplies each element of the parameter vector by 5, and then adds
those new products to the new vector. Finally, the new vector is
returned. To print the returned vector, use another enhanced for loop
to iterate through the vector after it has been initialized.

vector<int> MultiplyFive(vector<int>& my_list) {


vector<int> new_list;
for (auto a : my_list) {
new_list.push_back(a * 5);
}
return new_list;
}

int main() {
vector<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);
numbers.push_back(4);
numbers.push_back(5);

vector<int> print_list = MultiplyFive(numbers);


for (auto a : print_list) {
cout << a << endl;
}

return 0;
}

Alternatively, you can also type the function as void which results in
fewer lines of code.
void MultiplyFive(vector<int>& my_list) {
vector<int> new_list;
for (auto a : my_list) {
new_list.push_back(a * 5);
}
for (auto a : new_list) {
cout << a << endl;
}
}

int main() {
vector<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);
numbers.push_back(4);
numbers.push_back(5);

MultiplyFive(numbers);
return 0;
}
Helper Functions

Helper Functions
Helper functions are functions that are called from within other functions.
Take, for example, the formula for calculating the area of a circle:

It would be quite easy to write a C++ function to calculate the area of a


circle. However, instead of knowing the radius of the circle, you have the
X/Y coordinates for a point at the center of the circle and another point on
the circle. The distance formula (which is based on the Pythagorean
Theorem) can calculate the radius of the circle.

.guides/img/Radius

The FindRadius() function uses the distance formula to calculate the


distance between 2 pairs of points. The FindArea() function finds the area
of a circle by relying on the FindRadius() function. Therefore, the
FindRadius() function is a helper function. Helper functions help shorten
how much code is needed to accomplish certain tasks.

/**
* This function finds the radius of a circle given
* two coordinate points
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return The radius of a circle in double
*/
double FindRadius(double x1, double y1, double x2, double y2) {
return(sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)));
}

/**
* This function finds the area of a circle given
* two coordinate points
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return The area of a circle in double
*/
double FindArea(double x1, double y1, double x2, double y2) {
return(M_PI * pow(FindRadius(x1, y1, x2, y2), 2));
}

int main() {
cout << FindArea(0.0, 0.0, 4.0, 4.0) << endl;
return 0;
}
info

Math Functions
Note that in order to perform certain functions such as finding a
square or an exponent, we need to include <math.h> in our header as
well as to define M_PI which represents pi. If you remove these from
the program header, the math functions associated with <math.h> will
no longer work. In essence, these functions also serve as helper
functions.
Lab: Parameters

The Slope Formula


You are going to write a function that takes in 4 doubles as parameters.
These parameters represent two sets of coordinate points labeled as x1, y1,
x2, and y2. The function will then use these points to calculate the slope that
their line creates and then prints that slope to the user.

Function Header
First, we need to set up the function header. As usual, we will start off with
our return type. Since the result is simply printing the slope, we will use
void as the return type. Additionally, we’ll name the function GetSlope().

void GetSlope() {
}

Parameters
The function should take 4 doubles as parameters named x1, y1, x2, and y2.

void GetSlope(double x1, double y1, double x2, double y2) {


}

Printing the Slope


The final step is to print the slope, but we’ll need the slope formula in order
to do that. The slope formula is defined as (y2 - y1) / (x2 - x1).

cout << (y2 - y1) / (x2 - x1) << endl;

Testing the Function


In order to use a function, you’ll need to call it by specifying its name
within the main() function. Note that the function requires parameters so
we’ll need to provide some arguments in order for the function to work
properly. Let’s use the points (3, 2) and (5, 6) as our coordinates which
correspond to (x1, y1) and (x2, y2) respectively. Lastly, it is a best
practice to include return 0 as the last statement inside main().

int main() {
GetSlope(3, 2, 5, 6);
return 0;
}

The GetSlope() function will apply the slope formula (6 - 2) / (5 - 3)


and print the result 2.0 to the user. Make sure to also include
documentation so that other users can understand your function.

Code

/**
* This function prints the slope between two sets
* of coordinate points
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return No return value
*/
void GetSlope(double x1, double y1, double x2, double y2) {
cout << (y2 - y1) / (x2 - x1) << endl;
}

int main() {
GetSlope(3, 2, 5, 6);
return 0;
}
Lab: Variable Scope

Local and Global Variables


For this lab, we are going to be adding local and global variables to our
previously created GetSlope() function. Remember that global variables
exist outside of functions while local variables exist inside functions.
Depending on how you declare your local and global variables, they will
behave differently per situation.

Global Variables
First, let’s add some global variables to our program.

double input1;
double input2;
double input3;
double input4;

The GetSlope() Function


As from before, the function will still take 4 doubles as parameters named
x1, y1, x2, and y2. However, we’re going to implement two different
calculations within the function. Specifically, we are going to calculate the
difference between the y coordinates first, then calculate the difference
between the x coordinates. These calculations will then be assigned to local
variables called y_change and x_change. Finally, the function will print the
quotient between y_change and x_change, which is also the slope itself.

void GetSlope(double x1, double y1, double x2, double y2) {


double y_change = y2 - y1;
double x_change = x2 - x1;
cout << y_change / x_change << endl;
}

Testing the Function


To make things more dynamic, we’ll actually make use of a cin within the
main() function. cin will take in inputs from the user and assign them to
our 4 global variables input1, input2, input3, and input4. These inputs will
later correspond to x1, y1, x2, and y2. Having cin enables the user to decide
what the coordinate points will be.

int main() {
cout << "Enter first x coordinate: " << endl;
cin >> input1;
cout << "Enter first y coordinate: " << endl;
cin >> input2;
cout << "Enter second x coordinate: " << endl;
cin >> input3;
cout << "Enter second y coordinate: " << endl;
cin >> input4;

GetSlope(input1, input2, input3, input4);


}

You’ll notice that you have access to the Terminal which you will use to
input any coordinate points you want. If you enter 3, 2, 5, and 6
respectively, you should get 2 since cout removes all trailing zeros. Click the
TRY IT button to compile and run the program.

Code
double input1; //global
double input2; //global
double input3; //global
double input4; //global

/**
* This function prints the slope between two sets
* of coordinate points by calculating their coordinate
* changes separately
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return No return value
*/
void GetSlope(double x1, double y1, double x2, double y2) {
double y_change = y2 - y1;
double x_change = x2 - x1;
cout << y_change / x_change << endl;
}

int main() {
cout << "Enter first x coordinate: " << endl;
cin >> input1;
cout << "Enter first y coordinate: " << endl;
cin >> input2;
cout << "Enter second x coordinate: " << endl;
cin >> input3;
cout << "Enter second y coordinate: " << endl;
cin >> input4;

GetSlope(input1, input2, input3, input4);


}

info

Program Flow
After the program is initiated, the global variables will be created first.
Next, main() will run. Although commonly written last, main() will
always be the first function to run by default in C++. The lines of code
within main() will be executed in the order of their appearance.
Lab: Return Values

Returning a Value
When the result of a function is simply a print statement, it is considered to
be a void function. void functions do not have a return type, meaning they
do not return data back to the user. To return data, use the keyword return
followed by the data. Note that functions with return must be declared
with same data type as the data that they return. For example, a function
that returns an double must be declared in the header as a double function.

double GetSlope(double x1, double y1,


double x2, double y2) { //replace void with
double
double y_change = y2 - y1;
double x_change = x2 - x1;
return y_change / x_change; //returns a double
}

Modifying the Return Value


Notice that our function returns a single double, which is nice but not
extremely helpful when it comes to determining rise and run for slopes
(rise / run). Let’s say we want instead to express the slope in the rise /
run format. rise is the change in y values and run is the change in x values.
Unfortunately, we can’t simply do return y_change + " / " + x_change.
Why? Because the " / " is a string which is not compatible with the
current return value of double. One way around this is to convert the
doubles into strings. Doing so will force us to change our double function
into a string function.

string GetSlope(double x1, double y1,


double x2, double y2) { //replace double with
string
double y_change = y2 - y1;
double x_change = x2 - x1;
return to_string(y_change) + " / " + to_string(x_change);
//returns a string
}

Notice how we need to use to_string() to convert our doubles into strings.
Completing the Program
Now just copy over the rest of the program that we had previously written.

double input1;
double input2;
double input3;
double input4;

/**
* This function returns the slope between two sets
* of coordinate points by calculating their coordinate
* changes separately
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return A string expression of the slope in rise / run format
*/
string GetSlope(double x1, double y1,
double x2, double y2) {
double y_change = y2 - y1;
double x_change = x2 - x1;
return to_string(y_change) + " / " + to_string(x_change);
}

int main() {
cout << "Enter first x coordinate: " << endl;
cin >> input1;
cout << "Enter first y coordinate: " << endl;
cin >> input2;
cout << "Enter second x coordinate: " << endl;
cin >> input3;
cout << "Enter second y coordinate: " << endl;
cin >> input4;

GetSlope(input1, input2, input3, input4);


}

Printing the Slope


If we try to run the program, we will not see anything printed to the screen.
Why? Because there is no print statement anywhere within the code. All
the program does is calculate and return values. Returning values and
printing them are not the same thing. Therefore, we need to include a print
statement if we want to actually see the output. However, we cannot just
include a print statement within our function because it is a string
function, not a void one. Fortunately, we can use our main() function to
print our desired output.

double input1;
double input2;
double input3;
double input4;

/**
* This function returns the slope between two sets
* of coordinate points by calculating their coordinate
* changes separately
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return A string expression of the slope in rise / run format
*/
string GetSlope(double x1, double y1,
double x2, double y2) {
double y_change = y2 - y1;
double x_change = x2 - x1;
return to_string(y_change) + " / " + to_string(x_change);
}

int main() {
cout << "Enter first x coordinate: " << endl;
cin >> input1;
cout << "Enter first y coordinate: " << endl;
cin >> input2;
cout << "Enter second x coordinate: " << endl;
cin >> input3;
cout << "Enter second y coordinate: " << endl;
cin >> input4;

cout << GetSlope(input1, input2, input3, input4) << endl;


//prints what is returned by the GetSlope() function
}
Lab: Helper Functions

Purpose of Helper Functions


When a function calls another function, it is using that function to help it
perform a particular action. Helper functions provide users with more
flexibility when it comes to developing functions. Additionally, helper
functions help reduce code repetition because the same action only has to
be written once. Let’s start by creating a few helper functions that will help
us with other functions later.

/**
* This function returns the difference in y values
*
* @param y1 A double of the first y-coordinate
* @param y2 A double of the second y-coordinate
* @return The difference of y1 and y2 as a double
*/
double GetRise(double y1, double y2) {
return y2 - y1;
}

/**
* This function returns the difference in x values
*
* @param x1 A double of the first x-coordinate
* @param x2 A double of the second x-coordinate
* @return The difference of x1 and x2 as a double
*/
double GetRun(double x1, double x2) {
return x2 - x1;
}

Above, we have two functions. One that calculates the rise of a slope and
another that calculates the run of a slope. These two helper functions will
come in handy in out later slope calculations.

Using Helper Functions


/**
* This function returns the slope in decimal form
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return A double expression of the slope
*/
double GetSlopeDecimal(double x1, double y1,
double x2, double y2) {
return GetRise(y1, y2) / GetRun(x1, x2);
}

/**
* This function returns the slop in fraction form
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return A string expression of the slope in rise / run format
*/
string GetSlopeFraction(double x1, double y1,
double x2, double y2) {
return to_string(GetRise(y1, y2)) + " / " +
to_string(GetRun(x1, x2));
//need to convert doubles to strings!
}

Notice how within the two functions above GetSlopeDecimal() and


GetSlopeFraction(), the previous helper functions GetRise() and GetRun()
are called. Having 4 functions at our disposal provides us with a flexibility
that a single function cannot offer. In this program, we can get the slope in
its decimal form and its fraction form in addition to the rise and run
individually. If we wanted, we can continue to build more into this
program.

Complete and Run the Program


Copy over the rest of the program and then test it.

double input1;
double input2;
double input3;
double input4;
/**
* This function returns the difference in y values
*
* @param y1 A double of the first y-coordinate
* @param y2 A double of the second y-coordinate
* @return The difference of y1 and y2 as a double
*/
double GetRise(double y1, double y2) {
return y2 - y1;
}

/**
* This function returns the difference in x values
*
* @param x1 A double of the first x-coordinate
* @param x2 A double of the second x-coordinate
* @return The difference of x1 and x2 as a double
*/
double GetRun(double x1, double x2) {
return x2 - x1;
}

/**
* This function returns the slope in decimal form
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return A double expression of the slope
*/
double GetSlopeDecimal(double x1, double y1,
double x2, double y2) {
return GetRise(y1, y2) / GetRun(x1, x2);
}

/**
* This function returns the slop in fraction form
*
* @param x1 A double of the first x-coordinate
* @param y1 A double of the first y-coordinate
* @param x2 A double of the second x-coordinate
* @param y2 A double of the second y-coordinate
* @return A string expression of the slope in rise / run format
*/
string GetSlopeFraction(double x1, double y1,
double x2, double y2) {
return to_string(GetRise(y1, y2)) + " / " +
return to_string(GetRise(y1, y2)) + " / " +
to_string(GetRun(x1, x2));
}

int main() {
cout << "Enter first x coordinate: " << endl;
cin >> input1;
cout << "Enter first y coordinate: " << endl;
cin >> input2;
cout << "Enter second x coordinate: " << endl;
cin >> input3;
cout << "Enter second y coordinate: " << endl;
cin >> input4;

cout << "Rise: ";


cout << GetRise(input2, input4) << endl;
cout << "Run: ";
cout << GetRun(input1, input3) << endl;
cout << "Calculated form: ";
cout << GetSlopeDecimal(input1, input2, input3, input4) <<
endl;
cout << "Slope form: ";
cout << GetSlopeFraction(input1, input2, input3, input4) <<
endl;
}
Lab Challenge: Greeting Machine

Create a Greeting Machine


You are going to develop a function that takes a vector of strings as a
parameter, iterates through that vector and greets every element in it with
"Hello" followed by a newline.

Existing Code:

#include <iostream>
#include <vector>
using namespace std;

//add code below this line

//add code above this line

int main(int argc, char** argv) {


vector<string> names;
for (int i = 1; i < argc; i++) {
names.push_back(argv[i]);
}
SayHello(names);
}

Requirements

You should not make any changes to the code that already exists. If you
accidentally delete any existing code, you can copy and paste the entire
program from above.
You can use any number of additional functions you’d like but you
must include at least the function called SayHello() in your code.

Compile and test your code with a few different values


create

Test with Alan & Bob


Expected Output
Hello Alan
Hello Bob

create

Test with 1, 2 & 3


Expected Output
Hello 1
Hello 2
Hello 3

create

Test with Codio


Expected Output
Hello Codio
Learning Objectives: Recursion
Define recursion

Identify the base case

Identify the recursive pattern


What is Recursion

What is Recursion?
Solving a coding problem with functions involves breaking down the
problem into smaller problems. When these smaller problems are
variations of the larger problem (also know as self-similar), then recursion
can be used. For example, the mathematical function factorial is self-
similar. Five factorial (5!) is calculated as 5 * 4 * 3 * 2 * 1. Mouse over
the image below to see that 5! is really just 5 * 4!, and 4! is really just 4 *
3! and so on.

Because 5! is self-similar, recursion can be used to calculate the answer.


Recursive functions are functions that call themselves. Copy the following
code into the text editor on your left and click TRY IT to test the code.
#include <iostream>
using namespace std;

//add function definitions below this line

/**
* Calculates factorial using recursion
*
* @param n, integer
* @return factorial of n, integer
*/
int Factorial(int n) {
if (n == 1) {
return 1;
}
else {
return n * Factorial(n - 1);
}
}

//add function definitions above this line

int main() {

//add code below this line

cout << Factorial(5) << endl;


return 0;

//add code above this line

Optional: Click the Code Visualizer link below to see how C++ handles this
recursive function behind-the-scenes.

Code Visualizer

Recursion is an abstract and difficult topic, so it might be a bit hard to


follow what is going on here. When n is 5, C++ starts a multiplication
problem of 5 * Factorial(4). The function runs again and the
multiplication problem becomes 5 * 4 * Factorial(3). This continues
until n is 1. C++ returns the value 1, and C++ solves the multiplication
problem 5 * 4 * 3 * 2 * 1. The video below should help explain how 5! is
calculated recursively.
Error

The Base Case


Each recursive function has two parts: the recursive case (where the
function calls itself with a different parameter) and the base case (where
the function stops calling itself and returns a value).

.guides/img/CppRecursion

The base case is the most important part of a recursive function. Without it,
the function will never stop calling itself. Like an infinite loop, C++ will stop
the program with an error. Replace the function in your code with the one
below and see what happens.

/**
* This recursive function returns an error
*
* @param n, integer
* @return factorial of n, integer
*/
int Factorial(int n) {
return n * Factorial(n - 1);
}

Code Visualizer
Always start with the base case when creating a recursive function. Each
time the function is called recursively, the program should get one step
closer to the base case.

challenge

What happens if you:


Change the Factorial() function to look like:

int Factorial(int n) {
if (n == 1) { //base case
return 1;
}
else { //recursive case
return n * Factorial(n - 1);
}
}

Change the print statement to cout << Factorial(0) << endl;?

Try to modify the base case so that Factorial(0) does not result in
an error.

Test your new base case with a negative number.

Solution

The factorial operation only works with positive integers. So the


base case should be:

int Factorial(int n) {
if (n <= 0) {
return 1;
}
else {
return n * Factorial(n - 1);
}
}

Code Visualizer
Fibonacci Sequence

Fibonacci Number
A Fibonacci number is a number in which the current number is the sum
of the previous two Fibonacci numbers.

Fibonacci Sequence

Calculating a Fibonacci number is self-similar, which means it can be


defined with recursion. Setting the base case is important to avoid infinite
recursion. When the number n is 0 the Fibonacci number is 0, and when n
is 1 the Fibonacci number is 1. So if n is less than or equal to 1, then return
n. That is the base case.

/**
* @param n, integer
* @return Fibonacci number of n, integer
*/
int Fibonacci(int n) {
if (n <= 1) {
return n;
}
else {
return(Fibonacci(n-1) + Fibonacci(n-2));
}
}

int main() {
cout << Fibonacci(3) << endl;
return 0;
}

Code Visualizer
challenge

What happens if you:


Change the print statement to cout << Fibonacci(0) << endl;?
Change the print statement to cout << Fibonacci(8) << endl;?
Change the print statement to cout << Fibonacci(30) << endl;?

Where is the code visualizer?


The code visualizer will only step through your code 1,000 times. These
recursive functions exceed this limit and generate an error message.
Because of this, the code visualizer was removed.

Fibonacci Sequence
Fibonacci numbers are most often talked about as a sequence. The main()
function below adds the functionality of printing a Fibonacci sequence of a
predetermined length. Replace your current main() function with the one
below and TRY IT.

int main() {
int fibonacci_length = 4;
for (int i = 0; i < fibonacci_length; i++) {
cout << Fibonacci(i) << endl;
}
return 0;
}

Code Visualizer

challenge

What happens if you:


Change fibonacci_length to 10?
Change fibonacci_length to 30?
Change fibonacci_length to 50?

Why is C++ timing out?


The code written above is terribly inefficient. Each time through the loop,
C++ is calculating the same Fibonacci numbers again and again. When i is
1, C++ calculates the Fibonacci numbers for 0 and 1. When i is 2, C++ is
calculating the Fibonacci numbers for 0, 1, and 2. Once i becomes large
enough, it becomes too much work for C++ to have to recalculate these
large numbers over and over again. There is a more efficient way to do this
by using vector. The idea is to store previously calculated Fibonacci
numbers in the vector. So instead of recalculating the same numbers again
and again, you can get these numbers from the vector. If a Fibonacci
number is not in the vector, then calculate it and add it to the vector. Copy
and paste the code below into the IDE if you want to run it.

NOTE: long is a data type that can hold much larger values than int can.
Thus, for larger numbers, long is necessary.

long Fibonacci(long n) {
static vector<long> v = {0, 1};

if (n < v.size())
return v.at(n);
else {
v.push_back(Fibonacci(n - 1) + Fibonacci(n - 2));
return v.at(n);
}
}

int main() {
int fib_length = 50;
for (int i = 0; i < fib_length; i++) {
cout << Fibonacci(i) << endl;
}
return 0;
}
Lab 1

Lab 1 - Recursive Tree

Recursive Tree

Trees can be drawn recursively. Draw a branch. At the end of the branch,
draw two smaller branches with one to the left and the other to the right.
Repeat until a certain condition is true. This program will walk you
through drawing a tree in this way.

Turtle Graphics Review


We will be using Turtle Graphics to visualize recursion. Here is some
review on what a Turtle object (tina) can do in C++:

Turtle Graphics Review

tina.forward(n) - Where n represents the number of pixels.


tina.backward(n) - Where n represents the number of pixels.
tina.right(d) - Where d represents the number of degrees.
tina.left(d) - Where d represents the number of degrees.
tina.pencolor({“COLOR”}) - Where COLOR represents the track or line
color you want tina to leave behind.
tina.width(W) - Where W represents how wide (in pixels) tina’s track is.
tina.shape(“SHAPE”) - Where SHAPE represents the shape tina takes.
tina.speed(SPEED) - Where SPEED represents how fast tina moves
Command Parameter Examples
Where COLOR
represents the
red, orange, yellow,
tina.pencolor({"COLOR"}) track or line color
green, blue, purple
you want tina to
leave behind
Where W
represents how any positive integer
tina.width(W)
wide (in pixels) (e.g. 1, 10, 123, etc.)
tina’s track is
Where SHAPE
triangle, indented
tina.shape("SHAPE") represents the
triangle, square, arrow
shape tina takes
TS_FASTEST, TS_FAST,
Where SPEED
TS_NORMAL,
tina.speed(SPEED) represents how
TS_SLOW,
fast tina moves
TS_SLOWEST

And some instructions on how Turtle Graphics work on the Terminal:

.guides/img/TurtleGraphicsFlow

1. TRY IT button is clicked by the user.


2. The Terminal tab is opened.
3. The terminal runs the command to compile the program and to display
the graphical output.
4. The output is displayed as a screen on the bottom left panel. You can
click the screen to close the output.
5. Click on the file name tab to go back to the text editor if you want to
make changes to the program.

Program Instructions
Let’s start by creating a canvas screen and a Turtle object tina in main() to
allow the Turtle object to move around on. Feel free to edit the screen size
so that it fits comfortably on your monitor. You’ll also notice that there is
function called RecursiveTree(). This function takes three parameters,
branch_length, angle, and t.

Note that when passing an object (like a Turtle), you should should pass it
as a reference using the & symbol (i.e. Turtle& t).

This is the code you have so far in the text editor:

////////// DO NOT EDIT HEADER! //////////


#include <iostream> //
#include "CTurtle.hpp" //
#include "CImg.h" //
using namespace cturtle; //
using namespace std; //
/////////////////////////////////////////

/**
* @param branch_length An integer
* @param angle The angle of degree
* @param t A Turtle object
* @return A drawing symbolizing a tree branch
*/
void RecursiveTree(int branch_length, int angle, Turtle& t) {

//add function definitions below

//add function definitions above

int main(int argc, char** argv) {

//add code below this line

//add code above this line

screen.exitonclick();
return 0;

}
The base case for this function is a bit different. In previous examples, if
the base case is true a value was returned. The function RecursiveTree()
does not return a value, it draws on the screen instead. So the base case
will be to keep recursing as long as branch_length is greater than some
value. Define the base case as branch_length as being greater than 5.

void RecursiveTree(int branch_length, int angle, Turtle& t) {

//add function definitions below

if (branch_length > 5) {

//add function definitions above

Start drawing the tree by going forward and turning right. Then call
RecursiveTree() again, but reduce branch_length by 15. The code should
run, but the tree will not look like a tree. It looks more like a curve made of
a series of line segments decreasing in size.

void RecursiveTree(int branch_length, int angle, Turtle& t) {

//add function definitions below

if (branch_length > 5) {
t.forward(branch_length);
t.right(angle);
RecursiveTree(branch_length - 15, angle, t);
}

//add function definitions above

In main(), let’s call the RecursiveTree() function and pass in some initial
values.
int main(int argc, char** argv) {

//add code below this line

TurtleScreen screen(400, 300);


Turtle tina(screen);
RecursiveTree(45, 20, tina);

//add code above this line

screen.exitonclick();
return 0;

The next step is to draw the branch that goes off to the left. Since the turtle
turned to the right the number of degrees that the parameter angle
represents, the turtle needs to turn to the left twice the degrees of angle.
Turning to the left angle will put the turtle back at its original heading. The
turtle needs to go further to the left. Then draw another branch whose
length is reduced by 15.

void RecursiveTree(int branch_length, int angle, Turtle& t) {

//add function definitions below

if (branch_length > 5) {
t.forward(branch_length);
t.right(angle);
RecursiveTree(branch_length - 15, angle, t);
t.left(angle * 2);
RecursiveTree(branch_length - 15, angle, t);
}

//add function definitions above

The tree is looking better, but there are two more things that need to be
done. First, put the turtle back to its original heading by turning right angle
degrees. Then go backwards the length of the branch. If you tweak some of
the arguments when calling the RecursiveTree() function, you might notice
the tree changing.
void RecursiveTree(int branch_length, int angle, Turtle& t) {

//add function definitions below

if (branch_length > 5) {
t.forward(branch_length);
t.right(angle);
RecursiveTree(branch_length - 15, angle, t);
t.left(angle * 2);
RecursiveTree(branch_length - 15, angle, t);
t.right(angle);
t.backward(branch_length);
}

//add function definitions above

challenge

What happens if you:


Increase the branch length argument when calling RecursiveTree()
in main() for the first time such as 35 or 60?
Increase and decrease the angle argument when calling
RecursiveTree() in main() for the first time such as 10 or 40?
Change all of the recursive cases in the function from
branch_length - 15 to something smaller like branch_length - 5?
Change the base case to if (branchLength > 1) in the function?
Rotate the tina 90 degrees to the left before calling RecursiveTree()
in main() for the first time?

Code Sample

////////// DO NOT EDIT HEADER! //////////


#include <iostream> //
#include "CTurtle.hpp" //
#include "CImg.h" //
using namespace cturtle; //
using namespace std; //
/////////////////////////////////////////

/**
* @param branch_length An integer
* @param angle The angle of degree
* @param t A Turtle object
* @return A drawing symbolizing a tree branch
*/
void RecursiveTree(int branch_length, int angle, Turtle& t) {

//add function definitions below

if (branch_length > 5) {
t.forward(branch_length);
t.right(angle);
RecursiveTree(branch_length - 5, angle, t);
t.left(angle * 2);
RecursiveTree(branch_length - 5, angle, t);
t.right(angle);
t.backward(branch_length);
}

//add function definitions above

int main(int argc, char** argv) {

//add code below this line

TurtleScreen screen(400, 300);


Turtle tina(screen);
tina.left(90); //rotates Turtle's original position
tina.speed(TS_FASTEST); //speeds up Turtle's movement
RecursiveTree(35, 20, tina);

//add code above this line

screen.exitonclick();
return 0;

}
Lab 2

Lab 2 - The Hilbert Curve

Hilbert Curve

The Hilbert Curve is a fractal, space-filling curve. Start by creating a Turtle


object, and then write the function header for the recursive function
Hilbert. The parameters for the function are the distance the turtle will
travel, the rule to be used, an angle (determines how tight the fractal is),
depth (how intricate the fractal is), and the Turtle object.

This is the code you have so far in the text editor:


////////// DO NOT EDIT HEADER! //////////
#include <iostream> //
#include "CTurtle.hpp" //
#include "CImg.h" //
using namespace cturtle; //
using namespace std; //
/////////////////////////////////////////

/**
* @param dist, integer
* @param rule, integer
* @param angle, integer
* @param depth, integer
* @param t, Turtle
* @return A drawing of the Hilbert Curve
*/
void Hilbert(int dist, int rule, int angle, int depth, Turtle&
t) {

//add function definitions below

//add function definitions above

int main(int argc, char** argv) {

//add code below this line

TurtleScreen screen(400, 300);


Turtle tina(screen);

//add code above this line

screen.exitonclick();
return 0;

The base case for the function is when depth is 0. Another way to think
about the base case is that if depth is greater than 0, keep drawing the
fractal. Use if (depth > 0) as the base case. Also, there are two rules for
the turtle. Ask if rule is equal to 1 or if it is equal to 2.
void Hilbert(int dist, int rule, int angle, int depth, Turtle&
t) {

//add function definitions below

if (depth > 0) {
if (rule == 1) {
//rule1 code
}
if (rule == 2) {
//rule2 code
}
}

//add function definitions above

The code continues with if rule is equal to 1, then the turtle is going to turn
left, recursively call the Hilbert() function with rule set to 2, go forward,
turn right, recursively call the Hilbert() function with rule set to 1, go
forward, recursively call the Hilbert() function with rule set to 1, turn
right, and finally move forward. Because the base case is based on depth, it
must be reduced by 1 each time the Hilbert() function is called
recursively.

if (rule == 1) {
//rule1 code
t.left(angle);
Hilbert(dist, 2, angle, depth - 1, t);
t.forward(dist);
t.right(angle);
Hilbert(dist, 1, angle, depth - 1, t);
t.forward(dist);
Hilbert(dist, 1, angle, depth - 1, t);
t.right(angle);
t.forward(dist);
Hilbert(dist, 2, angle, depth - 1, t);
t.left(angle);
}

If rule is equal to 2, then the code is almost the inverse of when rule is
equal to 1. The turtle will still go forward, but left turns become right turns,
right turns become left turns, and recursive calls to Hilbert() will use 2
instead of 1 for the rule parameter (and vice versa).
if (rule == 2) {
//rule2 code
t.right(angle);
Hilbert(dist, 1, angle, depth - 1, t);
t.forward(dist);
t.left(angle);
Hilbert(dist, 2, angle, depth - 1, t);
t.forward(dist);
Hilbert(dist, 2, angle, depth - 1, t);
t.left(angle);
t.forward(dist);
Hilbert(dist, 1, angle, depth - 1, t);
t.right(angle);
}

Finally, call the Hilbert() function in main() and run the program to see
the fractal.

int main(int argc, char** argv) {

//add code below this line

TurtleScreen screen(400, 300);


Turtle tina(screen);
Hilbert(5, 1, 90, 5, tina);

//add code above this line

screen.exitonclick();
return 0;

Speeding up the turtle


The Hilbert Curve can be slow to draw. You can change the speed of the
Turtle tina with the following command tina.speed(TS_FASTEST); before
calling the Hilbert() function.
challenge

What happens if you:


Change the dist parameter to 3?
Start with the rule parameter as 2?
Change the angle parameter to 85?
Change the depth parameter to 4?

Note: You might need to adjust your TurtleScreen’s size to capture all
of the output.

Sample Code

////////// DO NOT EDIT HEADER! //////////


#include <iostream> //
#include "CTurtle.hpp" //
#include "CImg.h" //
using namespace cturtle; //
using namespace std; //
/////////////////////////////////////////

/**
* @param dist, integer
* @param rule, integer
* @param depth, integer
* @param t, Turtle
* @return A drawing of the Hilbert Curve
*/
void Hilbert(int dist, int rule, int angle, int depth, Turtle&
t) {

//add function definitions below

if (depth > 0) {
if (rule == 1) {
//rule1 code
t.left(angle);
Hilbert(dist, 2, angle, depth - 1, t);
t.forward(dist);
t.right(angle);
Hilbert(dist, 1, angle, depth - 1, t);
t.forward(dist);
Hilbert(dist, 1, angle, depth - 1, t);
t.right(angle);
t.forward(dist);
Hilbert(dist, 2, angle, depth - 1, t);
t.left(angle);
}
if (rule == 2) {
//rule2 code
t.right(angle);
Hilbert(dist, 1, angle, depth - 1, t);
t.forward(dist);
t.left(angle);
Hilbert(dist, 2, angle, depth - 1, t);
t.forward(dist);
Hilbert(dist, 2, angle, depth - 1, t);
t.left(angle);
t.forward(dist);
Hilbert(dist, 1, angle, depth - 1, t);
t.right(angle);
}
}

//add function definitions below

int main(int argc, char** argv) {

//add code below this line

TurtleScreen screen(400, 300);


Turtle tina(screen);
tina.speed(TS_FASTEST);
Hilbert(8, 1, 90, 4, tina);

//add code above this line

screen.exitonclick();
return 0;

}
Lab Challenge

Lab Challenge
Problem
Write a recursive function called RecursivePower() that takes two integers
as parameters. The first parameter is the base number and the second
parameter is the exponent. Return the base number parameter to the
power of the exponent.

DO NOT edit any existing code or you will not receive credit for your work!

#include <iostream>
using namespace std;

//add function definitions below this line

//add function definitions above this line

int main(int argc, char** argv) {


cout << RecursivePower(stoi(argv[1]), stoi(argv[2])) << endl;
return 0;
}

Expected Output
* If the function call is RecursivePower(5, 3), then the function will return
125.
* If the function call is RecursivePower(4, 5), then the function will return
1024.

Compile and test your code with a few different values

Expected Output
216

Expected Output
1
Learning Objectives: Classes and
Objects

Define the terms class, objects, instance, and instantiate

Identify the difference between classes and objects

Create a user-defined object

Modify an object’s attribute with dot notation

Define a constructor

Create a copy of an object


Built-In Objects

The String Object and Others


You have already been using built-in C++ objects. Strings are an example of
a C++ object.

string s = "I am a string";


cout << "s is a: " << typeid(s).name() << endl;

challenge

Try these variations:


Explore some of the functions associated with the string class.
* Add the line of code cout << boolalpha << s.empty() << endl;
* Add the line of code cout << s.length() << endl;
* Add the line of code s.push_back('s'); and then cout << s << endl;

C++ says that the class or type of s is


NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE (which is a
string). Replace the exiting code with the one below and run the program
again.

int arr[1];
cout << "arr is a: " << typeid(arr).name() << endl;

The resulting output says arr is a: A1_i. A1 stands for one dimensional
array and i stands for integer.

Vocabulary
In the text above, the words “class” and “object” are used in an almost
interchangeable manner. There are many similarities between classes and
objects, but there is also an important difference. Working with objects has
a lot of specialized vocabulary.
Classes - Classes are a collection of data and the actions that can modify the
data. Programming is a very abstract task. Classes were created to give
users a mental model of how to think about data in a more concrete way.
Classes act as the blueprint. They tell C++ what data is collected and how it
can be modified.

Objects - Objects are constructed according to the blueprint that is the


class. In the code above, the variable s is a string object. It is not the class.
The string class tells C++ that s has functions like length, append, and
replace. When a programmer wants to use a class, they create an object.

Instance - Another way that programmers talk about objects is to say that
an object is an instance of a particular class. For example, s is an instance
of the string class.

Instantiation - Instantiation is the process where an object is created


according to a blueprint of the class. The phrase “define a variable” means
to create a variable. The variable is given a name and a value. Once it has
been defined, you can use the variable. With objects, you use the phrase
“instantiate an object”. That means to create an object, give it a name, store
any data, and define the actions the object can perform.

.guides/img/objects/cpp_class_v_object.png
User-Defined Objects

Defining an Object
Assume you want to collect information about actors. Creating a class is a
good way to keep this data organized. The class keyword is used to define
a class. For now, do not add anything as the body of the class.

//add class definitions below this line

class Actor {

};

//add class definitions above this line

Naming classes

The convention for naming classes in C++ is to use a capital letter. A


lowercase letter will not cause an error message, but it is not considered to
be “correct”. If a class has a name with multiple words, all of the words are
pushed together, and a capital letter is used for the first letter of each word.
This is called camel case.

Classes are just the blueprint. To you use a class, you need to instantiate an
object. Here is an object to represent Helen Mirren. Be sure to put this code
in the main function.

//add code below this line

Actor helen;

//add code above this line

So you now have helen, which is now an instance of the Actor class.

Adding Attributes
The point of having a class is to collect information and define actions that
can modify the data. The Actor class should contain things like the name of
the actor, notable films, awards they have won, etc. These pieces of
information related to a class are called attributes. Attributes are declared
in the class itself. The example below adds the first_name and last_name
attributes which are both strings. Notice that a keyword is also required
public. public is considered to be an access specifier which determines
how accessible the attributes are from outside the class. Adding this
keyword just means that the attributes first_name and last_name are
readily accessible. For now, we will be using public as the access specifier
for our classes.

//add class definitions below this line

class Actor {
public:
string first_name;
string last_name;
};

//add class definitions above this line

You can change the value of an attribute with the assignment operator,
object_name.attribute = attribute_value. Notice that you always use
object_name.attribute to reference an attribute. This is called dot notation.
Once an attribute has a value, you can treat it like any other variable. Add
the following code to the main function. You are assigning values to the
attributes fist_name and last_name, and then printing these values.

//add code below this line

Actor helen;
helen.first_name = "Helen";
helen.last_name = "Mirren";
cout << helen.first_name + ' ' + helen.last_name << endl;

//add code above this line


challenge

Try these variations:


Add the attribute int total_films; to the class and then assigned
helen.total_films = 80; in main.
Add the print statement cout << helen.total_films << endl; in
main.
Add the print statement cout << helen << endl;.

Note that many objects in C++ cannot be printed directly, thus cout <<
helen << endl; resulted in an error. When printing objects, be sure to
reference their attributes.
The Constructor

Too Much Code


Imagine that the Actor class has more attributes than on the previous page.

//add class definitions below this line

class Actor {
public:
string first_name;
string last_name;
string birthday;
int total_films;
int oscar_nominations;
int oscar_wins;
};

//add class definitions above this line

Now create an object for Helen Mirren with values for each attribute.
Adding each attribute individually requires several lines of code. This is
especially true if you have more than one instance of the Actor class.

//add code below this line

Actor helen;
helen.first_name = "Helen";
helen.last_name = "Mirren";
helen.birthday = "July 26";
helen.total_films = 80;
helen.oscar_nominations = 4;
helen.oscar_wins = 1;
cout << helen.first_name + ' ' + helen.last_name << endl;

//add code above this line

The class Actor creates a class and its attributes. It does not assign value to
any attributes; the user has to do this. A class is supposed to be a blueprint.
It should lay out all of the attributes and their values for the user. Classes
can do this when you use the constructor.
The Constructor
The constructor is a special function for a class. Its job is to assign value for
attributes associated with the object. These attributes can also be called
instance variables. In C++, the constructor is the class name, parentheses,
and curly brackets. Inside of the constructor, give attributes their values.

//add class definitions below this line

class Actor {
public:
string first_name;
string last_name;
string birthday;
int total_films;
int oscar_nominations;
int oscar_wins;

Actor() {
first_name = "Helen";
last_name = "Mirren";
birthday = "July 26";
total_films = 80;
oscar_nominations = 4;
oscar_wins = 1;
}
};

//add class definitions above this line

Instantiating helen as an instance of the Actor class automatically calls the


constructor. Since the instance variables (attributes) have values, you can
remove those lines of code from the main function.

//add code below this line

Actor helen;
cout << helen.first_name + ' ' + helen.last_name << endl;

//add code above this line


challenge

Try these variations:


Add this print statement to the main function:

cout << helen.first_name + ' ' + helen.last_name + "\'s


birthday is " + helen.birthday + '.' << endl;

Add this print statement to the main function:

cout << helen.first_name + ' ' + helen.last_name + " won " +


helen.oscar_wins + " Oscar(s) out of " +
helen.oscar_nominations + " nomination(s)." << endl;

Change all of the + above to <<.

When you attempted to print cout << helen.first_name + ' ' +


helen.last_name + " won " + helen.oscar_wins + " Oscar out of " +
helen.oscar_nominations + " nominations" << endl;, you likely received a
very long error message. This happened because the operator + only works
with same-type objects or data. In the print statement above, you tried to
combine strings with integers which C++ did not like and therefore
complained. To solve this, simply change the + to <<.
The Constructor and Parameters

The Constructor and Parameters


Now imagine that you want to use the Actor class to instantiate an object
for Helen Mirren and Tom Hanks. Create the Actor class just as before.

//add class definitions below this line

class Actor {
public:
string first_name;
string last_name;
string birthday;
int total_films;
int oscar_nominations;
int oscar_wins;

Actor() {
first_name = "Helen";
last_name = "Mirren";
birthday = "July 26";
total_films = 80;
oscar_nominations = 4;
oscar_wins = 1;
}
};

//add class definitions above this line

Now instantiate two Actor objects, one for Helen Mirren and the other for
Tom Hanks. Print the fist_name and last_name attributes for each object.

//add code below this line

Actor helen;
Actor tom;
cout << helen.first_name << ' ' << helen.last_name << endl;
cout << tom.first_name << ' ' << tom.last_name << endl;

//add code above this line


The constructor Actor class only creates an object with information about
Helen Mirren. You can make the Actor class more flexible by passing it an
argument for each of attributes in the constructor. Parameters for the
constructor function work just as they do for user-defined functions, be
sure to indicate the data type for each parameter.

//add class definitions below this line

class Actor {
public:
string first_name;
string last_name;
string birthday;
int total_films;
int oscar_nominations;
int oscar_wins;

Actor(string fn, string ln, string bd, int tf, int on, int ow)
{
first_name = fn;
last_name = ln;
birthday = bd;
total_films = tf;
oscar_nominations = on;
oscar_wins = ow;
}
};

//add class definitions above this line

When you instantiate the two Actor objects, you can pass the constructor
the relevant information for both Helen Mirren and Tom Hanks. The code
should now print the correct first and last names.

//add code below this line

Actor helen("Helen", "Mirren", "July 26", 80, 4, 1);


Actor tom("Tom", "Hanks", "July 9", 76, 5, 2);
cout << helen.first_name << ' ' << helen.last_name << endl;
cout << tom.first_name << ' ' << tom.last_name << endl;

//add code above this line


challenge

Try these variations:


Create an instance of the Actor class for Denzel Washington
(December 28, 47 films, 8 nominations, 2 wins).
Print the birthday and total_films attributes for the newly created
object.

Code

Your code for the object representing Denzel Washington should look
something like this:

//add code below this line

Actor denzel("Denzel", "Washington", "December 28",


47, 8, 2);
cout << denzel.birthday << endl;
cout << denzel.total_films << endl;

//add code above this line

Default Values
We can assume that the average actor probably has not been nominated or
won an Oscar. So instead of making these attributes parameters for the
constructor, we can give them the default value of 0. These attributes can
always be updated later on.
//add class definitions below this line

class Actor {
public:
string first_name;
string last_name;
string birthday;
int total_films;
int oscar_nominations;
int oscar_wins;

Actor(string fn, string ln, string bd, int tf) {


first_name = fn;
last_name = ln;
birthday = bd;
total_films = tf;
oscar_nominations = 0;
oscar_wins = 0;
}
};

//add class definitions above this line

You can update the attributes once the object has been instantiated if need
be.

//add code below this line

Actor helen("Helen", "Mirren", "July 26", 80);


cout << helen.oscar_nominations << endl;
cout << helen.oscar_wins << endl;

helen.oscar_nominations = 4;
helen.oscar_wins = 1;

cout << helen.oscar_nominations << endl;


cout << helen.oscar_wins << endl;

//add code above this line


Copying Objects

Copying an Object
In C++, you can initialize a new object to an existing one to create a clone.
What do you thin the code below does?

//add class definitions below this line

class ComicBookCharacter {
public:
string name;
int age;
string type;
};

//add class definitions above this line

int main() {

//add code below this line

ComicBookCharacter a;
a.name = "Calvin";
a.age = 6;
a.type = "human";

ComicBookCharacter b = a;
a.name = "Hobbes";

cout << "Object a name: " << a.name << endl;


cout << "Object a age: " << a.age << endl;
cout << "Object a type: " << a.type << endl;
cout << "Object b name: " << b.name << endl;
cout << "Object b age: " << b.age << endl;
cout << "Object b type: " << b.type << endl;

//add code above this line

You’ll notice that the initializing one object to another created an exact
copy of the original object. Each object is still treated as separate objects
though so you can still freely change the attribute of one object without
affecting another.

challenge

Try these variations:


Add b.name = "Snoopy"; before the print statements.
Add b.type = "dog"; before the print statements.
Lab 1

Lab 1: Defining Your Own Object


When defining an object, there are a few criteria that must be met in order
for an object to be successfully created.

class ClassName {
public:
type attribute1;
type attribute2;
};

1. All objects are created inside classes. The first step is use the keyword
class.
2. Give the class a name which is used to construct an object.
3. The keyword public: is needed in order to provide access to object
attributes that you define later on.
4. Give your object as many attributes as needed in order to make full use
of your object.
5. All attributes go within curly braces {} after the class name declaration.
Make sure to end the closing curly brace with a semi-colon ;.

Student Object
Let’s define an object called Student. When we think of a student, some
information or attributes that we might associate with students are:
* Name
* Student ID number
* Major
* GPA
* Age
* Year of graduation

Once we’ve narrowed down what attributes we want associated with our
object, we can start defining them.
class Student {
public:
string name;
int ID;
string major;
double GPA;
int age;
int YOG;
};

Creating the Object


Once the class has been established, we can create the object by calling on
the object’s class and giving the object a name in the main function.

Student andy;
andy.name = "Andy";
andy.ID = 123456;
andy.major = "Computer Science";
andy.GPA = 3.45;
andy.age = 22;
andy.YOG = 2021;

Printing the Object’s Attributes


It is not sufficient to simply say cout << andy; in order to print the
attributes associated with andy. Instead, we must use dot notation to
specify what attribute of andy we want to output. To print andy’s ID for
example, use cout << andy.ID;. Or to print andy’s major, use cout <<
andy.major;. Add the following to the existing code and click the TRY IT
button to see what is printed about andy.

cout << andy.name << " is " << andy.age;


cout << " years old and is graduating with a degree in ";
cout << andy.major << " in " << andy.YOG << ".";
Lab 2

Lab 2: Building a Constructor


Defining an object and then having to use dot notation to assign values to it
every time can be a long and difficult task. To help alleviate that issue, we
can build a constructor to help us create an object with specified
attributes.

A Default Constructor
A constructor works similarly to a function in that you can define
parameters within the constructor. Then when it’s time to call the
constructor, you can just simply give it the appropriate arguments and the
object can be made. Let’s return to our Student object.
//add class definitions below this line

class Student {
public:
string name;
int ID;
string major;
double GPA;
int age;
int YOG;

Student() {
name = "Andy";
ID = 123456;
major = "Computer Science";
GPA = 3.45;
age = 22;
YOG = 2021;
}
};

//add class definitions above this line

int main() {

//add code below this line

Student mary;
cout << mary.name << "'s student ID is " << mary.ID << "." <<
endl;

mary.name = "Mary";
mary.GPA = 3.78;

cout << mary.name << " has a current GPA of " << mary.GPA <<
"." << endl;

//add code above this line

return 0;

Before, we had to use dot notation to assign values to our object. But having
the constructor, we can build it in a way that it will have default values
when the object is created. However, notice how the object mary has all of
the attributes of andy.
Constructors with Parameters
The default constructor makes all objects an andy object when they are
built. To change the attributes of the object, we can still use dot notation
(i.e. mary.name = "Mary";). However, most Students are unique and to have
to reassign value every time a default constructor is used can still be a
small challenge.

To make the constructor more flexible, we can give it parameters. A


constructor with parameters works similarly to a user-defined function in
which you provide the parameter types and the user simply has to provide
the arguments.
//add class definitions below this line

class Student {
public:
string name;
int ID;
string major;
double GPA;
int age;
int YOG;

Student(string n, int id, string m, double g, int a, int y) {


name = n;
ID = id;
major = m;
GPA = g;
age = a;
YOG = y;
}
};

//add class definitions above this line

int main() {

//add code below this line

Student andy("Andy", 123456, "Computer Science", 3.45, 22,


2021);
Student mary("Mary", 456789, "Mathematics", 3.78, 21, 2022);

cout << mary.name << " is a student in the " << mary.major <<
" department." << endl;
cout << mary.name << " is a junior while " << andy.name << "
is a senior." << endl;

//add code above this line

return 0;

A constructor with parameters enables the user to decide what attributes to


assign right when the object is created. The user just has to provide those
attributes as arguments in parentheses (i.e. Student mary("Mary", 456789,
"Mathematics", 3.78, 21, 2022);).
Lab Challenge

Lab Challenge
Create the variable dog1, and instantiate it as an object of the Dog class. This
dog’s name is Marceline and she is a German Shepherd. Create the variable
dog2 and make it a copy of dog1. dog2 should be named Cajun and have the
breed Belgian Malinois.

Your goal for this assignment is to design the class Dog so that the above can
be implemented successfully.

Expected Output

Test your code by printing the name and breed of each dog to make sure they
fulfill the requirements above. Most importantly, the third print statement
will print false.

Marceline German Shepherd


Cajun Belgian Malinois
false

DO NOT CHANGE the existing code in main.

Dog dog1("Marceline", "German Shepherd");


Dog dog2 = dog1;
dog2.name = "Cajun";
dog2.breed = "Belgian Malinois";

cout << dog1.name << " " << dog1.breed << endl;
cout << dog2.name << " " << dog2.breed << endl;
if (dog1.name == dog2.name && dog1.breed == dog2.breed) {
cout << boolalpha << true;
}
else {
cout << boolalpha << false;
}
Learning Objectives: Mutability

Define the term mutable

Construct an external function to modify class variables


(attributes)
Mutability and External Functions

Mutability
Objects are mutable, which means that objects (specifically their attributes)
can change value. Think of a video game; the main character in the game is
constantly changing. It could be their position on the screen, the score,
their health, the items in their inventory, etc. Imagine a simple class called
Player. A newly instantiated Player object has a health of 100, a score of 0,
and starts on level 1. This object can lose health, increase their score, and
advance levels.

//add class definitions below this line

class Player {
public:
int health;
int score;
int level;

Player() {
health = 100;
score = 0;
level = 1;
}
};

//add class definitions above this line

Print out the attributes of player1. Then change each attribute and print
out the attributes again.
//add code below this line

Player player1;
cout << "This player has " << player1.health << " health, a
score of " << player1.score;
cout << ", and is on level " << player1.level << "." << endl;
player1.health -= 10;
player1.score += 25;
player1.level += 1;
cout << "This player has " << player1.health << " health, a
score of " << player1.score;
cout << ", and is on level " << player1.level << "." << endl;

//add code above this line

challenge

Try these variations:


Change the health of player1 to 0.
Print the status of player1 specifying that their health is 0 and the
message Game over..
One Possible Solution

player1.health = 0;
cout << "This player has " << player1.health << " health.
Game over." << endl;

External Functions and Objects


One of the benefits of functions is code reusability. The example above has
a repetition of the cout statement. This is a good opportunity to use a
function.

//add function definitions below this line

void PrintPlayer(Player p) {
cout << "This player has " << p.health << " health, a score of
" << p.score;
cout << ", and is on level " << p.level << "." << endl;
}

//add function definitions above this line


In the main function, replace the strings inside the print statements with a
call to the PrintPlayer function. Don’t forget to pass the player1 object to
the PrintPlayer function.

//add code below this line

Player player1;
PrintPlayer(player1);
player1.health -= 10;
player1.score += 25;
player1.level += 1;
PrintPlayer(player1);

//add code above this line

Using an external function to print the status of player1 may not seem like
it was worth the effort to change the code. But when these functions
become more complex, the efficiency becomes clear.

//add function definitions below this line

void PrintPlayer(Player p) {
if (p.health <= 0) {
cout << "This player is dead. They died on level " <<
p.level;
cout << " with a score of " << p.score << "." << endl;
}
else {
cout << "This player has " << p.health << " health, a score
of " << p.score;
cout << ", and is on level " << p.level << "." << endl;
}
}

//add function definitions above this line

Now that the PrintPlayer function can return two different strings, call the
function when the player1 object has full health, and call it again when the
object has no health.
//add code below this line

Player player1;
PrintPlayer(player1);
player1.health = 0;
player1.score += 25;
player1.level += 1;
PrintPlayer(player1);

//add code above this line

The problem with using external functions, however, is that the changes
made to objects in one function do not translate or carry over to the next
function.

#include <iostream>
using namespace std;

//add class definitions below this line

class Player {
public:
int health;
int score;
int level;

Player() {
health = 100;
score = 0;
level = 1;
}
};

//add class definitions above this line

//add function definitions below this line

void PrintPlayer(Player p) {
if (p.health <= 0) {
cout << "This player is dead. They died on level " <<
p.level;
cout << " with a score of " << p.score << "." << endl;
}
else {
cout << "This player has " << p.health << " health, a score
of " << p.score;
cout << ", and is on level " << p.level << "." << endl;
}
}

void ChangeHealth(Player p, int amount) {


p.health += amount;
cout << "New health = " << p.health << endl;
}

//add function definitions above this line

int main() {

//add code below this line

Player player1;
PrintPlayer(player1);
player1.health = 0;
player1.score += 25;
player1.level += 1;
PrintPlayer(player1);

ChangeHealth(player1, 20); //changes health of player1


PrintPlayer(player1); //does not register changes from
ChangeHealth function

//add code above this line

return 0;

You’ll notice above that ChangeHealth(player1, 20) had no effect on


PrintPlayer(player1). player1’s health changed to 20 but after it leaves the
function, it returned to 0. Changes that occur within external functions are
not permanent. Next, you will be introduced to class functions which will
enable you to make changes to objects that are more permanent.
Learning Objectives: Class
Functions

Define the term class function

Convert an external function that modifies an object


into a class function

Demonstrate the syntax for defining and calling a class


function
External Functions vs. Class
Functions

Class Functions
Back in the Introduction to Objects module, a class was defined as “a
collection of data and the actions that can modify the data.” The
constructor can build the “collection of data”, but nothing in the class can
modify the data. Instead, external functions were used to modify the object.
However, using external functions to modify objects is not a good practice.
Here, you will be introduced to class functions, also known as class or
instance methods, that serve to modify the data within objects.

Think of a class function as a function that is attached to an object. The


class function is the most common type of function when creating classes.
Notice how class functions are declared inside of the class. These functions
are called class functions because they have access to the class variables
(the attributes declared in the constructor). Class functions are invoked
using dot-notation.

.guides/img/mutability/ExternalVsClassFunctions

There are a few notable differences between external functions and class
functions.
1. In order for external functions to work, class variables within a class
must be public. Otherwise, the function will not be able to act on the object.
This, however, is not a good practice.
1. In C++, it is a best practice to make class variables private. Doing so
prevents external functions from accidentally making undesirable changes
to the class attributes. This is why class functions are preferred when
modifying objects.
1. Everything within the class is public in the external function example. In
contrast, class attributes are private while constructors and functions are
public in the class function example.
1. To modify an object using an external function, the syntax is
Function(Object) (i.e. ChangeLevel(mario)). On the other hand, the syntax
for using a class function is Object.Function() (i.e. mario.ChangeLevel()).

Converting to Class Functions


When mutability was first introduced, you made a Player class with a few
external functions. You are now going to transform these external
functions into class functions moving forward. The Player class will be
defined just as before. This time, however, PrintPlayer will be a part of the
class.

//add class definitions below this line

class Player {
public: //public access modifer
Player() { //constructor
health = 100;
score = 0;
level = 1;
}
void PrintPlayer() { //class function
if (health <= 0) {
cout << "This player is dead. They died on level " <<
level;
cout << " with a score of " << score << "." << endl;
}
else {
cout << "This player has " << health << " health, a
score of " << score;
cout << ", and is on level " << level << "." << endl;
}
}

private: //private access modifiers


int health;
int score;
int level;
};

//add class definitions above this line


In main, instantiate a Player object. Then call the class function PrintPlayer
using dot-notation. Be sure to label the appropriate public and private
access modifiers!

//add code below this line

Player mario;
mario.PrintPlayer();

//add code above this line

challenge

Try this variation:


Call PrintPlayer like this:

Player mario;
PrintPlayer(mario);

Why did this generate an error?


C++ says that ‘PrintPlayer’ was not declared in this scope even
though the definition is within the class Player. This happens because
the code is using an external function call. Currently, PrintPlayer is a
class function within the Player class. In order to access a class
function, dot notation must be used.

More Player Methods


The next class functions to add to the Player class are those to print the
health and level attributes of the Player object. Start with the class
function ChangeHealth. This function takes amount as an int parameter.
ChangeHealth will add amount to the health attribute. If a player’s health
increases, amount is positive. If their health decreases, amount is negative.
Add ChangeHealth directly below PrintPlayer().
void PrintPlayer() { //class function
if (health <= 0) {
cout << "This player is dead. They died on level " << level;
cout << " with a score of " << score << "." << endl;
}
else {
cout << "This player has " << health << " health, a score of
" << score;
cout << ", and is on level " << level << "." << endl;
}
}
void ChangeHealth(int amount) {
health += amount;
}

The class function NextLevel is going to be similar to ChangeHealth except


for one difference. NextLevel has no parameters. In video games, players go
up in levels; rarely do they decrease. So the level attribute will increase by
one when the class function NextLevel is called.

void ChangeHealth(int amount) {


health += amount;
}
void NextLevel() {
level++;
}

Change main to:

//add code below this line

Player mario;
mario.PrintPlayer();
mario.ChangeHealth(25);
mario.NextLevel();
mario.PrintPlayer();

//add code above this line

Then TRY IT.


challenge

Try these variations:


Change mario.ChangeHealth(25); to mario.ChangeHealth(-25);.
Add another mario.NextLevel(); below the first
mario.NextLevel();.
Create a class function to change a player’s score by a set integer
amount. Then try to call it.
One possible solution

//class function
void ChangeScore(int amount) {
score += amount;
}

//main
mario.ChangeScore(123);

Why learn about external functions that modify objects when C++
has class functions?
It might seem like a waste of time to learn how to write external functions
that modify objects, but this approach builds upon concepts you have
already seen — external functions and objects. This allows you to
understand mutability without having to worry about class functions. Once
you understand how these ideas work, transforming an external function
into an class function is much simpler. External functions that modify
objects serve as an intermediary step on the way to learning about class
functions.
More Class Functions

More on Class Methods and Objects


Changes to objects should happen exclusively through class functions. This
makes your code easier to organize and easier for others to understand.
Imagine you are going to create a class that keeps track of a meal. In this
case, a meal can be thought of as all of the drinks, appetizers, courses, and
desserts served. Each one of these categories will become a class variable
(attribute). Assign each attribute a vector of strings. Remember, class
variables/attribute are private.

//add class definitions below this line

class Meal {
private:
vector<string> drinks;
vector<string> appetizers;
vector<string> main_courses;
vector<string> desserts;
};

//add class definitions above this line

Next, add a class function to add a drink to the Meal object. Use the
push_back function to add an element to the vector. So
drinks.push_back(drink) adds the drink drink to the vector drinks. Then
add a class function PrintDrinks to print out all of the elements inside the
drinks vector. Class functions are public.
//add class definitions below this line

class Meal {
public:
void AddDrink(string drink) {
drinks.push_back(drink);
}
void PrintDrinks() {
for (auto a: drinks) {
cout << a << endl;
}
}

private:
vector<string> drinks;
vector<string> appetizers;
vector<string> main_courses;
vector<string> desserts;
};

//add class definitions above this line

Create a Meal object in main and then test your code with the following
added commands.

//add code below this line

Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();

//add code above this line

Now create the AddAppetizer class function for the class. Like the AddDrink
function above, AddAppetizer accepts a string as a parameter and adds it as
an element to the appetizers attribute (which is a vector). Then create a
PrintAppetizers function to print what’s inside the appetizers vector.
void AddDrink(string drink) {
drinks.push_back(drink);
}
void PrintDrinks() {
for (auto a: drinks) {
cout << a << endl;
}
}
void AddAppetizer(string app) {
appetizers.push_back(app);
}
void PrintAppetizers() {
for (auto a: appetizers) {
cout << a << endl;
}
}

Add "bruschetta" as an appetizer to the dinner object, then call the class
function PrintAppetizers like below.

//add code below this line

Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();
dinner.AddAppetizer("bruschetta");
dinner.PrintAppetizers();

//add code above this line

challenge

Create the following class functions:


AddMainCourse - accepts a string which represents a main course
and adds it to the meal.

PrintMainCourses - prints all of the main courses in the meal.

AddDessert - accepts a string which represents a dessert and adds it


to the meal.

PrintDesserts - prints all of the desserts in the meal.


Test your code using "roast chicken" as a main course and
"chocolate cake" as a dessert. Then use the Print class functions
you created to print out all of the items of the meal.

Meal code

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Meal {
public:
void AddDrink(string drink) {
drinks.push_back(drink);
}
void PrintDrinks() {
for (auto a: drinks) {
cout << a << endl;
}
}
void AddAppetizer(string app) {
appetizers.push_back(app);
}
void PrintAppetizers() {
for (auto a: appetizers) {
cout << a << endl;
}
}
void AddMainCourse(string mc) {
main_courses.push_back(mc);
}
void PrintMainCourses() {
for (auto a: main_courses) {
cout << a << endl;
}
}
void AddDessert(string dessert) {
desserts.push_back(dessert);
}
void PrintDesserts() {
for (auto a: desserts) {
cout << a << endl;
}
}
private:
vector<string> drinks;
vector<string> appetizers;
vector<string> main_courses;
vector<string> desserts;
};

//add class definitions above this line

int main() {

//add code below this line

Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();
dinner.AddAppetizer("bruschetta");
dinner.PrintAppetizers();
dinner.AddMainCourse("roast chicken");
dinner.PrintMainCourses();
dinner.AddDessert("chocolate cake");
dinner.PrintDesserts();

//add code above this line

return 0;

}
Printing the Meal

Format the Entire Meal


Currently, you should have the following code the text editor:

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Meal {
public:
void AddDrink(string drink) {
drinks.push_back(drink);
}
void PrintDrinks() {
for (auto a: drinks) {
cout << a << endl;
}
}
void AddAppetizer(string app) {
appetizers.push_back(app);
}
void PrintAppetizers() {
for (auto a: appetizers) {
cout << a << endl;
}
}
void AddMainCourse(string mc) {
main_courses.push_back(mc);
}
void PrintMainCourses() {
for (auto a: main_courses) {
cout << a << endl;
}
}
void AddDessert(string dessert) {
desserts.push_back(dessert);
}
void PrintDesserts() {
for (auto a: desserts) {
cout << a << endl;
}
}

private:
vector<string> drinks;
vector<string> appetizers;
vector<string> main_courses;
vector<string> desserts;
};

//add class definitions above this line

int main() {

//add code below this line

Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();
dinner.AddAppetizer("bruschetta");
dinner.PrintAppetizers();
dinner.AddMainCourse("roast chicken");
dinner.PrintMainCourses();
dinner.AddDessert("chocolate cake");
dinner.PrintDesserts();

//add code above this line

return 0;

What you want to do next is to print all of the Meal attributes that you
have in a format that is concise, clear, and makes sense. The ideal output
should also take into consideration how many items there are. Here are
some sample output:

0 Item in the Category

Drinks: None

1 Item in the Category


Drinks: water

2 Items in the Category

Drinks: water and lemonade

3 Items in the Category

Drinks: water, lemonade, and tea

Modify the Class Functions


In order to print the desired results, you’ll have to modify the class
functions. In particular, you’ll want to include multiple conditionals to
select for the printing format that you want. Note that currently, an
enhanced for loop is used to iterate the vectors. The first three sample
output is more straightforward because you can just use the size function
to check the vector’s size and then use the at function to print either 0, 1, or
2 items like below:

void PrintDrinks() {
if (drinks.size() == 0) {
cout << "Drinks: None" << endl;
}
else if (drinks.size() == 1) {
cout << "Drinks: " << drinks.at(0) << endl;
}
else if (drinks.size() == 2) {
cout << "Drinks: " << drinks.at(0) << " and " <<
drinks.at(1) << endl;
}
}

However, how will you select for categories that have 3 or more items? See
if you can try doing so on your own. Run your code a couple of times using
PrintDrinks after adding different amounts of elements using AddDrink.

You can compare your solution to a sample one below:

Sample Code
void PrintDrinks() { //class definition
if (drinks.size() == 0) {
cout << "Drinks: None" << endl;
}
else if (drinks.size() == 1) {
cout << "Drinks: " << drinks.at(0) << endl;
}
else if (drinks.size() == 2) {
cout << "Drinks: " << drinks.at(0) << " and " <<
drinks.at(1) << endl;
}
else {
cout << "Drinks: ";
for (int i = 0; i < drinks.size() - 1; i++) {
cout << drinks.at(i) << ", ";
}
cout << "and " << drinks.at(drinks.size() - 1) << endl;
}
}

Meal dinner;
dinner.PrintDrinks();
dinner.AddDrink("water");
dinner.PrintDrinks();
dinner.AddDrink("lemonade");
dinner.PrintDrinks();
dinner.AddDrink("tea");
dinner.PrintDrinks();
dinner.AddDrink("coffee");
dinner.PrintDrinks();

Print the Entire Meal


Once you’ve completed modifying one class function. You can modify the
rest as specified. To print the entire meal, create a class function called
PrintMeal that incorporates all of the other Print functions. Once you’ve
done that, test your code with the following statements in main:
Meal dinner;
dinner.AddDrink("Pepsi");
dinner.AddDrink("Sprite");
dinner.AddAppetizer("egg rolls");
dinner.AddAppetizer("pot stickers");
dinner.AddAppetizer("buffalo wings");
dinner.AddMainCourse("smoked salmon");
dinner.PrintMeal();

Expected Output

Drink(s): Pepsi and Sprite


Appetizer(s): egg rolls, pot stickers, and buffalo wings
Main Course(s): smoked salmon
Dessert(s): None

Sample Code

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Meal {
public:
void AddDrink(string drink) {
drinks.push_back(drink);
}
void PrintDrinks() {
if (drinks.size() == 0) {
cout << "Drink(s): None" << endl;
}
else if (drinks.size() == 1) {
cout << "Drink(s): " << drinks.at(0) << endl;
}
else if (drinks.size() == 2) {
cout << "Drink(s): " << drinks.at(0) << " and " <<
drinks.at(1) << endl;
}
else {
cout << "Drink(s): ";
for (int i = 0; i < drinks.size() - 1; i++) {
cout << drinks.at(i) << ", ";
}
cout << "and " << drinks.at(drinks.size() - 1) << endl;
}
}
void AddAppetizer(string app) {
appetizers.push_back(app);
}
void PrintAppetizers() {
if (appetizers.size() == 0) {
cout << "Appetizers(s): None" << endl;
}
else if (appetizers.size() == 1) {
cout << "Appetizers(s): " << appetizers.at(0) << endl;
}
else if (appetizers.size() == 2) {
cout << "Appetizers(s): " << appetizers.at(0) << " and "
<< appetizers.at(1) << endl;
}
else {
cout << "Appetizers(s): ";
for (int i = 0; i < appetizers.size() - 1; i++) {
cout << appetizers.at(i) << ", ";
}
cout << "and " << appetizers.at(appetizers.size() - 1)
<< endl;
}
}
void AddMainCourse(string mc) {
main_courses.push_back(mc);
}
void PrintMainCourses() {
if (main_courses.size() == 0) {
cout << "Main Course(s): None" << endl;
}
else if (main_courses.size() == 1) {
cout << "Main Course(s): " << main_courses.at(0) <<
endl;
}
else if (main_courses.size() == 2) {
cout << "Main Course(s): " << main_courses.at(0) << "
and " << main_courses.at(1) << endl;
}
else {
cout << "Main Course(s): ";
for (int i = 0; i < main_courses.size() - 1; i++) {
cout << main_courses.at(i) << ", ";
}
cout << "and " << main_courses.at(main_courses.size() -
1) << endl;
}
}
void AddDessert(string dessert) {
desserts.push_back(dessert);
}
void PrintDesserts() {
if (desserts.size() == 0) {
cout << "Dessert(s): None" << endl;
}
else if (desserts.size() == 1) {
cout << "Dessert(s): " << desserts.at(0) << endl;
}
else if (desserts.size() == 2) {
cout << "Dessert(s): " << desserts.at(0) << " and " <<
desserts.at(1) << endl;
}
else {
cout << "Dessert(s): ";
for (int i = 0; i < desserts.size() - 1; i++) {
cout << desserts.at(i) << ", ";
}
cout << "and " << desserts.at(desserts.size() - 1) <<
endl;
}
}
void PrintMeal() {
PrintDrinks();
PrintAppetizers();
PrintMainCourses();
PrintDesserts();
}

private:
vector<string> drinks;
vector<string> appetizers;
vector<string> main_courses;
vector<string> desserts;
};

//add class definitions above this line

int main() {

//add code below this line

Meal dinner;
dinner.AddDrink("Pepsi");
dinner.AddDrink("Sprite");
dinner.AddAppetizer("egg rolls");
dinner.AddAppetizer("pot stickers");
dinner.AddAppetizer("buffalo wings");
dinner.AddMainCourse("smoked salmon");
dinner.PrintMeal();

//add code above this line

return 0;

}
Lab 1

Lab 1
For this lab, you will create a Student class that has the following private
class attributes:

string name - name of the student


int grade - student’s grade level
int score - test score of the student

First, let’s put together all of the class attributes.

class Student {
private:
string name;
int grade;
int score;
};

Next, let’s define the constructor Student with two parameters string n for
the student’s name and int g for the student’s grade.

class Student {
public:
Student(string n, int g) {
name = n;
grade = g;
}

private:
string name;
int grade;
int score;
};

Now, you want to define a class function called StudentStatus that takes a
student’s int score as a parameter and checks whether the score is a
passing score or not. A passing score is 65 or higher. If the score is less than
65, then the student did not pass their grade and will remain in the same
grade they are now. Otherwise, if the student has a score of 65 or higher,
then they have passed and will move on to the next grade and their grade
attribute will increase by 1. The function should also output a message
providing some context regarding whether the student has been promoted
to the next grade or not.

//add class definitions below this line

class Student {
public:
Student(string n, int g) {
name = n;
grade = g;
}
void StudentStatus(int s) {
if (s < 65) {
score = s;
cout << name << " has not graduated and will remain in
grade ";
cout << grade << "." << endl;
}
else {
score = s;
cout << name << " has graduated and will be promoted to
grade ";
cout << grade + 1 << "." << endl;
}
}

private:
string name;
int grade;
int score;
};

//add class definitions above this line

In main, try a few test cases to see if StudentStatus updates alice’s grade
level correctly.

//add code below this line

Student alice("Alice", 4);


alice.StudentStatus(60);
alice.StudentStatus(90);

//add code above this line


Since Alice received a score of 65 the first time, they were not promoted to
the next grade. However, once they got a score of 90 the second time
around, they were promoted to the next grade.
Lab 2

Lab 2
It is important to understand why class attributes are labeled as private.
This provides a level of protection for your code since it does not allow the
user to interact with the class attributes directly.

//add class definitions below this line

class Student {
public:
Student() {
name;
grade;
}

public:
string name = "Alice";
int grade = 4;
int score = 65;
};

//add class definitions above this line

Because the code above has public class attributes, the following code in
main can change those attributes’ values directly.

//add code below this line

Student steve;
steve.name = "Steve";
cout << steve.name << endl;

//add code above this line

However, if you change the class attributes from public to private, the
code in main will no longer work.
//add class definitions below this line

class Student {
public:
Student() {
name;
grade;
}

private:
string name = "Alice";
int grade = 4;
int score = 65;
};

//add class definitions above this line

//add code below this line

Student steve;
steve.name = "Steve";
cout << steve.name << endl;

//add code above this line

This is why understanding how class functions work is important. Class


functions serve as the intermediate step between the objects and the class
attributes. They are the ones interacting with the class attributes instead of
the user.
//add class definitions below this line

class Student {
public:
Student() {
name;
grade;
}
void ChangeName(string n) {
name = n;
}
string ReturnName() {
return name;
}

private:
string name = "Alice";
int grade = 4;
int score = 65;
};

//add class definitions above this line

//add code below this line

Student steve;
steve.ChangeName("Steve");
cout << steve.ReturnName() << endl;

//add code above this line

Although using class functions may result in longer code, it prevents the
user from seeing and interacting with the class attributes directly. This is
why using class attributes is a best practice.
Lab Challenge

Copy and paste the Zoo class below into the text editor.

//add class definitions below this line

class Zoo {
public:
Zoo(int bc, int p, int r, int b) {
big_cats = bc;
primates = p;
reptiles = r;
birds = b;
}

private:
int big_cats; //for "big cats"
int primates; //for "primates"
int reptiles; //for reptiles
int birds; //for birds
};

//add class definitions above this line

Your task is to add the following class functions to the class:


* TotalAnimals - returns the total number of animals
* TotalMammals - returns the number of mammals (which includes big_cats
and primates)
* MostAnimals - returns the name of the animal with the most count
assuming no two animals have the same count

DO NOT CHANGE the existing code in main or you will not pass the test:

Zoo my_zoo(10, 30, 90, 120);


cout << my_zoo.TotalAnimals() << endl;
cout << my_zoo.TotalMammals() << endl;
cout << my_zoo.MostAnimals() << endl;
Zoo my_zoo2(123, 45, 67, 89);
cout << my_zoo2.TotalAnimals() << endl;
cout << my_zoo2.TotalMammals() << endl;
cout << my_zoo2.MostAnimals() << endl;
Expected Result:

250
40
birds
324
168
big cats
Learning Objectives

Define the term encapsulation

Differentiate between public and private

Explain which parts of a class should be public or


private

Explain why encapsulation can be beneficial

Define data validation


What is Encapsulation?

What is Encapsulation?
Encapsulation is a concept in which related data and methods are grouped
together, and in which access to data is restricted. Grouping related data
and functions makes thinking about your program a bit easier. Hiding or
restricting how the user interacts with the data can keep the user from
making unwanted changes.

The two main ideas of data restriction are the public and private
keywords. These access modifiers (or keywords) can refer to classes,
functions, and attributes. public means that the constructor, function, or
attribute can be accessed both internally or externally. private means that
the constructor, attribute, or function can only be accessed internally
within the class itself.

Classes as Encapsulation
Classes in C++ are a form of encapsulation; they group together related data
and functions. In the code below, the attributes num1 and num2 are grouped
together with the functions Describe and Sum. They are all a part of
ExampleClass. The instance my_example is not a part of the class itself; it is
considered to be separate.
//add class definitions below this line

class ExampleClass {
void SetN(int n1, int n2) {
num1 = n1;
num2 = n2;
}

void Describe() {
cout << "My numbers are: " << num1 << " and " << num2 <<
endl;
}

int Sum() {
return num1 + num2;
}

int num1;
int num2;
};

//add class definitions above this line

//add code below this line

ExampleClass my_example;
my_example.SetN(5, 7);
my_example.Describe();
cout << my_example.Sum() << endl;

//add code above this line

The code above results in an error, but we’ll find out why next.

Hiding Data
You’ve learned in the Mutability chapter that class functions are typically
public and attributes are typically private. The public access modifier
enables other classes to have access to those functions. On the other hand,
the private access modifier disables access to attributes to prevent users
from imposing unwanted changes. Moving forward, we’ll abide by the
access modifier rules within the chart below.

Category Public Private


Constructor X
Functions X X
Attributes X

Why are functions both public and private?


In the pages that follow, you will see when making functions public is a
good idea, and when keeping functions private is preferable. A well
designed program will use a mix of public and private functions.
Previously, we’ve learned that helper functions can be kept private since
they are not directly accessed externally.

This is the same ExampleClass from above. It now uses the public and
private access modifiers to hide the data or to make them accessible.

//add class definitions below this line

class ExampleClass {
public:
void SetN(int n1, int n2) {
num1 = n1;
num2 = n2;
}

void Describe() {
cout << "My numbers are: " << num1 << " and " << num2 <<
endl;
}

int Sum() {
return num1 + num2;
}

private:
int num1;
int num2;
};

//add class definitions above this line

Note that when no access modifier is specified within a class, that attribute,
function, or constructor is automatically declared as private by default. To
make them public, you must specify public in the code.

Your code should run fine now because the instance or object is only
interacting with public information. Now try to print the values for the
num1 and num2 attributes.
//add code below this line

ExampleClass my_example;
my_example.SetN(5, 7);
cout << my_example.num1 << endl;
cout << my_example.num2 << endl;

//add code above this line

C++ produces an error message because an instance cannot directly access


a private attribute. This is an example of hiding data. my_example cannot
print num1 or num2 because they are private. However, my_example can
access the public methods, which can then access the private attributes.

challenge

Try this variation:


Create the functions PrintNum1 and PrintNum2 that print the num1
and num2 attributes.

Possible Solution

void PrintNum1() {
cout << num1 << endl;
}

void PrintNum2() {
cout << num2 << endl;
}

ExampleClass my_example;
my_example.SetN(5, 7);
my_example.PrintNum1();
my_example.PrintNum2();
Public Access Modifier

Public Attributes
While C++ allows you to make instance attributes public, this is not
encouraged. In fact, encapsulation asks that all attributes remain private.
C++ itself, however, allows for public attributes. The following class has
three attributes and all of them are public.

//add class definitions below this line

class Phone {
public:
Phone(string mo, int st, int me) {
model = mo;
storage = st;
megapixels = me;
}

string model;
int storage;
int megapixels;
};

//add class definitions above this line

Instantiate a Phone object and manipulate the different attributes.

//add code below this line

Phone my_phone("iPhone", 256, 12);


cout << my_phone.model << endl;
my_phone.storage = 64;
cout << my_phone.storage << endl;
cout << my_phone.megapixels + 10 << endl;

//add code above this line

When an attribute is public, a user can do whatever they want to it. This
can become problematic. In the code above, the phone’s storage was
reduced by 75%. This should not happen. Encapsulation limits what and
how information is modified. By hiding data, you can ensure that users
only manipulate the class in an approved manner.

Public Functions
Since all attributes should be private, we will use this access modifier for
the following code sample. Unlike attributes, you are encouraged to have
public functions. If all of your functions are private, it would be impossible
to interact with the object. The constructor is a special kind of function, and
this too should be public.

//add class definitions below this line

class Phone {
public:
Phone(string mo, int st, int me) {
model = mo;
storage = st;
megapixels = me;
}

private:
string model;
int storage;
int megapixels;
};

//add class definitions above this line

The real benefit of a public function is that it can access private attributes.
Public functions are the gateway to dealing with private data. Create the
public function Describe that prints a description of the Phone object.
//add class definitions below this line

class Phone {
public:
Phone(string mo, int st, int me) {
model = mo;
storage = st;
megapixels = me;
}

void Describe() {
cout << "My " << storage << " gig " << model;
cout << " has a " << megapixels << " megapixels camera."
<< endl;
}

private:
string model;
int storage;
int megapixels;
};

//add class definitions above this line

Instantiate a Phone object and call the describe method.

//add code below this line

Phone my_phone("iPhone", 256, 12);


my_phone.Describe();

//add code above this line


challenge

Try this variation


Change the access modifier from public to private.

Why does this not work?


The constructor is a special kind of function that is called when an
object is created. Once the constructor is private, it cannot be called
outside the class. That is why C++ throws an error message. The only
way a private constructor can work is if a class is declared inside
another class. The outer class can call the inner constructor even if it is
private.
Private Access Modifier

As discussed on the previous page, we will be making all attributes private.


Instance attributes, static attributes, constants — it does not matter, they
will all be private.

Private Functions
Functions too, can be private. And just like private attributes, private
functions are accessed by public functions. Here is an example class with a
private function.

//add class definitions below this line

class PrivateExample {
public:
PrivateExample(int n) {
num = n;
}

void PublicFunction() {
PrivateFunction();
}

private:
int num;

void PrivateFunction() {
cout << "The double of " << num << " is: " << num * 2 <<
endl;
cout << num << " squared is: " << num * num << endl;
}
};

//add class definitions above this line

Instantiate an object and try to call PrivateFunction.


//add code below this line

PrivateExample my_example(5);
my_example.PrivateFunction();

//add code above this line

C++ throws an error message because an instance cannot directly access a


private function. Change the function call to PublicMethod and run the code
again. This time it should work because public functions can access private
functions and/or attributes.

//add code below this line

PrivateExample my_example(5);
my_example.PublicFunction();

//add code above this line

Public and Private Methods


A well written C++ program will make use of both public and private
functions. Deciding what to make public and what to make private comes
down to how you want the user to interact with your code. Only make
public those functions you want the user to call. Keep everything else
private. The example below is a class that counts the number of vowels in a
strings.

First let’s add the private functions and attributes. Note that the IsVowel
and CountVowels functions will serve as helper functions in a later function.
This is why they do not need to be accessed directly by the user and should
be private.
//add class definitions below this line

class Words {
private:
string word;
int count;

bool IsVowel(char ch) {


ch = toupper(ch);
return (ch=='A' || ch=='E' || ch=='I' ||
ch=='O' || ch=='U');
}

int CountVowels(string str, int n) {


if (n == 1) {
return IsVowel(str[n-1]);
}
return CountVowels(str, n-1) + IsVowel(str[n-1]);
}
};

//add class definitions above this line

Next, add the public components such as the constructor Words. The
constructor instantiates an object with the word and count attributes. The
other public component is the Printer function, which calls the IsVowel
and CountVowels functions. Without this public Printer function, IsVowel
and CountVowels will be completely inaccessible.
//add class definitions below this line

class Words {
public:
Words(string str, int n) {
word = str;
count = n;
}

void Printer() {
cout << "The number of vowels in " << word;
cout << " is " << CountVowels(word, count) << endl;
}

private:
string word;
int count;

bool IsVowel(char ch) {


ch = toupper(ch);
return (ch=='A' || ch=='E' || ch=='I' ||
ch=='O' || ch=='U');
}

int CountVowels(string str, int n) {


if (n == 1) {
return IsVowel(str[n-1]);
}
return CountVowels(str, n-1) + IsVowel(str[n-1]);
}
};

//add class definitions above this line

Finally, instantiate a string to use as an argument and a Words object in


order to run the function Printer and see the program output.

//add code below this line

string s = "house";
Words vowels(s, s.length());
vowels.Printer();

//add code above this line


Learning Objectives - Getters and
Setters

Define the terms getter, setter, and data validation

Demonstrate how to access private attributes with


getters

Demonstrate how to change private attributes with


setters

Demonstrate validating data with setters


Getters

Getters
While all attributes are private, that does not mean that the user will not
need to access the values of these attributes. A public function can be used
to access a private attribute. This type of function has a special name, a
getter (also called an accessor). The whole purpose of a getter is to return
an attribute. These functions get their name because they always start with
Get followed by the attribute name.

//add class definitions below this line

class Phone {
public:
Phone(string mo, int s, int me) {
model = mo;
storage = s;
megapixels = me;
}

string GetModel() {
return model;
}

private:
string model;
int storage;
int megapixels;
};

//add class definitions above this line

The function GetModel is an example of a getter. Getters are very simple,


straightforward functions that do only one thing — return a private
attribute. Getters can be treated just as you would treat the attribute
(except for changing its value). To test a getter, you can call in main to see if
it returns what is expected.
//add code below this line

Phone my_phone("iPhone", 256, 12);


cout << my_phone.GetModel() << endl;

//add code above this line

challenge

Try this variation:


Create getters for the storage and megapixels attributes. Then call
them within main.

Possible Solution

//class definitions
public:
int GetStorage() {
return storage;
}

int GetMegapixels() {
return megapixels;
}

//main function
cout << my_phone.GetStorage() << endl;
cout << my_phone.GetMegapixels() << endl;

Benefits of Getters
Using a getter is the same thing as accessing a public attribute. Why not
make the attribute public? That would mean writing less code. Is that not a
good thing? A public attribute makes no distinction between accessing its
value and changing its value. If you can access it, you can change it (or vice
versa). Using a getter with a private attribute makes this distinction clear;
you can access the value, but you cannot change it.
//add code below this line

Phone my_phone("iPhone", 256, 12);


cout << my_phone.GetModel() << endl;
my_phone.model = "Pixel 5";

//add code above this line

The code above generates an error because an instance cannot alter a


private attribute. Using a getter allows limited access to an attribute, which
is preferable to the full access a public access modifier allows.
Setters

Setters
Setters are the compliment to getters in that they allow you to set the value
of a private attribute. Setter functions are also called mutators. Use the
Phone class from the previous page.

//add class definitions below this line

class Phone {
public:
Phone(string mo, int s, int me) {
model = mo;
storage = s;
megapixels = me;
}

string GetModel() {
return model;
}

int GetStorage() {
return storage;
}

int GetMegapixels() {
return megapixels;
}

private:
string model;
int storage;
int megapixels;
};

//add class definitions above this line

Add the SetModel method to the Phone class. As this is a setter method, start
the name with Set followed by the name of the attribute. Setters do not
return anything. Finally, setters have a parameter — the new value for the
attribute.
public:
// Setter
void SetModel(string new_model) {
model = new_model;
}

Now that you are implementing both getters and setters, you should now
be able to access and modify private attributes.

//add code below this line

Phone my_phone("iPhone", 256, 12);


cout << my_phone.GetModel() << endl;
my_phone.SetModel("XR");
cout << my_phone.GetModel() << endl;

//add code above this line


challenge

Try this variation:


Create setters for the storage and megapixels attributes. Then call them
within main.

Possible Solution

//class definitions
public:
void SetStorage(int new_storage) {
storage = new_storage;
}

void SetMegapixels(int new_megapixels) {


megapixels = new_megapixels;
}

//main function
my_phone.SetStorage(128);
cout << my_phone.GetStorage() << endl;
my_phone.SetMegapixels(6);
cout << my_phone.GetMegapixels() << endl;

Comparing Getters and Setters


Getters and setters have a lot in common. Their names are similar, they
have the same number of lines of code, etc. However, getters and setters
also differ in a few important ways. The table below highlights these
similarities and differences.

Category Getters Setters


Has public keyword X X
Has private keyword - -
Has return statement X -
Has void type - X
Performs only 1 task X X
Has parameter - X
Data Validation

C++ already has a type system which will flag errors when a boolean value
is passed to a function that takes an integer. However, just because a
function takes an integer does not mean that all integers are valid for that
function. Data validation is the process of asking if this data is appropriate
for its intended use. Take a look at the Person class.

//add class definitions below this line

class Person {
public :
Person(string n, int a) {
name = n;
age = a;
}

string GetName() {
return name;
}

void SetName(string new_name) {


name = new_name;
}

int GetAge() {
return age;
}

void SetAge(int new_age) {


age = new_age;
}

private:
string name;
int age;
};

//add class definitions above this line

The SetAge function will assign any value to the attribute age as long as the
value is an integer. There are some integers which make no sense when
thought of as an age attribute. The code sample below sets the age of
my_person to -100. -100 is a valid integer, but it is not a valid age. This is
why data validation is important. C++’s compiler is not sufficient to catch all
errors.

//add code below this line

Person my_person("Calvin", 6);


cout << my_person.GetName() << " is " << my_person.GetAge() <<
" years old." << endl;
my_person.SetAge(-100);
cout << my_person.GetName() << " is " << my_person.GetAge() <<
" years old." << endl;

//add code above this line

Another benefit of using setters is that data validation can take place before
the new value is assigned to the attribute. Modify SetAge so that it will only
update the age attribute if the new value is greater than or equal to 0. This
way you can ensure that the Person object always has a valid age.

void SetAge(int new_age) {


if (new_age >= 0) {
age = new_age;
}
}
challenge

Try these variations:


Change the data validation for the SetAge function so that values
over 200 or less than 0 are not valid.

Possible Solution

Here is one possible solution.

void SetAge(int new_age) {


if (new_age >= 0 && new_age <= 200) {
age = new_age;
}
}

Add data validation to the SetName function so that all strings with
one or more characters are valid.

Possible Solution

Here is one possible solution.

void SetName(string new_name) {


if (new_name != "") {
name = new_name;
}
}
Encapsulation Lab 1

This lab will focus on building on the idea of a “black box.” The term “black
box” is used to describe a system in which the internal workings are
hidden from the user. In fact, the user is not expected to know how the
system works; they only need to know how to use it. Encapsulation allows
you to create classes that are black boxes. Previously, we created a class
Words that took in a string and printed the number of vowels in that string.

.guides/img/Encapsulation/BlackBox3

In this lab, we are going to create a function that gives the user the ability
to put in a vector of strings and our program will print out the number of
vowels in each string within that vector.

//add code below this line

vector<string> list = {"house", "cake", "pancake"};


Words vowels(list);
vowels.CoutStrings();

//add code above this line

If you run the code above successfully in main, you should expect to see
3,2,3 as the output.

.guides/img/Encapsulation/BlackBox4

In this scenario, we are going to modify our previous Words class so that it
can include a vector. All of the following code will go into the class
definitions field.
class Words {
private:
vector<string> list_of_words;
};

We don’t need to reinvent the wheel; we previously worked on a few


functions that told us how many vowels exist in a specific string. We are
going to again re-use those functions. These are functions that the user does
not need to interact with. Thus, they can be private, essentially making
them act as part of the “black box.” Now, add the following private
functions into the Words class.

bool IsVowel(char ch) {


ch = toupper(ch);
return (ch=='A' || ch=='E' || ch=='I' ||
ch=='O' || ch=='U');
}

int CountVowels(string str, int n) {


if (n == 1) {
return IsVowel(str[n-1]);
}
return CountVowels(str, n-1) + IsVowel(str[n-1]);
}

Now that all of the data that we don’t want the user to manipulate are
properly encapsulated as private, we can start working on our public
members such as the constructor Words and the function CoutStrings. In
the example above, we can see our constructor takes in one attribute.

public:
Words(vector<string>& n){
list_of_words = n;
}

Another piece of information that we have from the main function is that
the function CoutStrings is used. This function has no arguments, but is
accessible to the user. This function also has several other tasks:

1. It iterates through a given vector


2. Counts the number of vowels in each given string
3. Creates a vector storing the vowel sizes
4. Prints out the output in a defined fashion
void CoutStrings() {
vector<int> vowel_sizes;
int size;
for (auto a : list_of_words) {
size = CountVowels(a, a.length());
vowel_sizes.push_back(size);
}
for (int i = 0; i < vowel_sizes.size(); i++) {
if (i == vowel_sizes.size()-1) {
cout << vowel_sizes.at(i) << endl;
}
else {
cout << vowel_sizes.at(i) << ',';
}
}
}

Full Code

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Words {
public:
Words(vector<string>& n){
list_of_words = n;
}

void CoutStrings() {
vector<int> vowel_sizes;
int size;
for (auto a : list_of_words) {
size = CountVowels(a, a.length());
vowel_sizes.push_back(size);
}
for (int i = 0; i < vowel_sizes.size(); i++) {
if (i == vowel_sizes.size()-1) {
cout << vowel_sizes.at(i) << endl;
}
else {
cout << vowel_sizes.at(i) << ',';
}
}
}

private:
vector<string> list_of_words;

bool IsVowel(char ch) {


ch = toupper(ch);
return (ch=='A' || ch=='E' || ch=='I' ||
ch=='O' || ch=='U');
}

int CountVowels(string str, int n) {


if (n == 1) {
return IsVowel(str[n-1]);
}
return CountVowels(str, n-1) + IsVowel(str[n-1]);
}
};

//add class definitions above this line

int main() {

//add code below this line

vector<string> list = {"house", "cake", "pancake"};


Words vowels(list);
vowels.CoutStrings();

//add code above this line

return 0;

Challenge
Can you modify the code so that it prints the number of non-vowels
instead of vowels? For example, vector<string> list_of_words =
{"house", "cake", "pancake"}; will have the following output: 2,2,4.

Possible Solution

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Words {
public:
Words(vector<string>& n){
list_of_words = n;
}

void CoutStrings() {
vector<int> counts;
int size;
for (auto a : list_of_words) {
size = CountNonVowels(a, a.length());
counts.push_back(size);
}
for (int i = 0; i < counts.size(); i++) {
if (i == counts.size()-1) {
cout << counts.at(i) << endl;
}
else {
cout << counts.at(i) << ',';
}
}
}

private:
vector<string> list_of_words;

bool IsNonVowel(char ch) {


ch = toupper(ch);
return !(ch=='A' || ch=='E' || ch=='I' ||
ch=='O' || ch=='U');
}

int CountNonVowels(string str, int n) {


if (n == 1) {
return IsNonVowel(str[n-1]);
}
return CountNonVowels(str, n-1) + IsNonVowel(str[n-
1]);
}
};

//add class definitions above this line


int main() {

//add code below this line

vector<string> list = {"house", "cake", "pancake"};


Words nonvowels(list);
nonvowels.CoutStrings();

//add code above this line

return 0;

}
Encapsulation Lab 2

In this next lab, we’ll continuing building our Words class to include a getter
and setter. These should be public to enable the main function to call them.

Full Code

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Words {
public:
Words(vector<string>& n){
list_of_words = n;
}

void CoutStrings() {
vector<int> vowel_sizes;
int size;
for (auto a : list_of_words) {
size = CountVowels(a, a.length());
vowel_sizes.push_back(size);
}
for (int i = 0; i < vowel_sizes.size(); i++) {
if (i == vowel_sizes.size()-1) {
cout << vowel_sizes.at(i) << endl;
}
else {
cout << vowel_sizes.at(i) << ',';
}
}
}

private:
vector<string> list_of_words;

bool IsVowel(char ch) {


ch = toupper(ch);
return (ch=='A' || ch=='E' || ch=='I' ||
ch=='O' || ch=='U');
}

int CountVowels(string str, int n) {


if (n == 1) {
return IsVowel(str[n-1]);
}
return CountVowels(str, n-1) + IsVowel(str[n-1]);
}
};

//add class definitions above this line

int main() {

//add code below this line

vector<string> list = {"house", "cake", "pancake"};


Words vowels(list);
vowels.CoutStrings();

//add code above this line

return 0;

First, we should determine what attribute to get and set. We currently have
only one attribute, list_of_words, which is used to store the list of strings.
However, what if we want to get a particular string? Or perhaps, set a
particular string at an index?

To be able to return a string from the vector, we’ll need to specify an index
or position. This means our getter function will need to take in an integer
parameter. However, there is a limitation to the index we can specify. We
cannot specify an index position that does not exist. Therefore, we’ll need
to validate the given parameter before returning anything.

string GetString(int i) {
if (i >= list_of_words.size()) {
return "No string exists at this index.";
}
return list_of_words.at(i);
}
GetString checks to see if the index exists before it returns a string within
the vector. If the index does not exist, No string exists at this index.
will be returned to the user. Otherwise, the function will return the string
at the specified index.

Next, let’s create our setter. This setter function will first check to see if the
index exists, then it will set a particular string specified by the user into
that index. Therefore, we’ll need two parameters for our setter.

void SetString(string s, int i) {


if (i >= list_of_words.size()) {
cout << "No string exists at this index." << endl;
}
list_of_words.at(i) = s;
}

Let’s test the code with the following commands in main.

//add code below this line

vector<string> list = {"house", "cake", "pancake"};


Words words(list);
cout << words.GetString(0) << endl;
words.SetString("mouse", 0);
cout << words.GetString(0) << endl;

//add code above this line

After the vector is accepted as a parameter, the GetString function is able


to return the string specified at index 0. This is why house is printed. Then,
SetString takes in mouse as a parameter and replaces the word at index 0
with it. GetString is then called again. Since mouse has replaced house, mouse
is printed during the second call.

Updated Code

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Words {
public:
Words(vector<string> n){
list_of_words = n;
}

string GetString(int i) {
if (i >= list_of_words.size()) {
return "No string exists at this index.";
}
return list_of_words.at(i);
}

void SetString(string s, int i) {


if (i >= list_of_words.size()) {
cout << "No string exists at this index." << endl;
}
list_of_words.at(i) = s;
}

void CoutStrings() {
vector<int> vowel_sizes;
int size;
for (auto a : list_of_words) {
size = CountVowels(a, a.length());
vowel_sizes.push_back(size);
}
for (int i = 0; i < vowel_sizes.size(); i++) {
if (i == vowel_sizes.size()-1) {
cout << vowel_sizes.at(i) << endl;
}
else {
cout << vowel_sizes.at(i) << ',';
}
}
}

private:
vector<string> list_of_words;

bool IsVowel(char ch) {


ch = toupper(ch);
return (ch=='A' || ch=='E' || ch=='I' ||
ch=='O' || ch=='U');
}

int CountVowels(string str, int n) {


if (n == 1) {
return IsVowel(str[n-1]);
}
return CountVowels(str, n-1) + IsVowel(str[n-1]);
}
};

//add class definitions above this line

int main() {

//add code below this line

vector<string> list = {"house", "cake", "pancake"};


Words words(list);
cout << words.GetString(0) << endl;
words.SetString("mouse", 0);
cout << words.GetString(0) << endl;

//add code above this line

return 0;

}
Lab Challenge

Lab Challenge
Problem
Write a class named Person that has attributes string name, int age, and
string occupation. These attributes should be private. Create getters and
setters for each attribute following C++ conventions.

Given Code

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

//add class definitions above this line

int main() {

//DO NOT EDIT CODE BELOW THIS LINE

Person p("Citra Curie", 16, "student");


cout << p.GetName() << endl;
p.SetName("Rowan Faraday");
cout << p.GetAge() << endl;
p.SetAge(18);
cout << p.GetOccupation() << endl;
p.SetOccupation("plumber");
cout << p.GetName() << endl;
cout << p.GetAge() << endl;
cout << p.GetOccupation() << endl;

//DO NOT EDIT CODE ABOVE THIS LINE

return 0;

}
Requirements
* Declare the instance Person("Citra Curie", 16, "student")
* The function GetName() returns Citra Curie
* The function SetName("Rowan Faraday") changes the name attribute to
“Rowan Faraday”
* The function GetAge() returns 16
* The function SetAge(18) changes the age attribute to 18
* The function GetOccupation() returns student
* The function SetOccupation("plumber") changes the occupation attribute
to “plumber”
* DO NOT EDIT the specified code in the main function or you may not
receive credit for your work!

Expected Output

Citra Curie
16
student
Rowan Faraday
18
plumber

Testing Your Code


Use the button below to test your code before submitting it for evaluation.
Learning Objectives: Base &
Derived Classes

Define the terms inheritance, base class, and derived


class

Explain the relationship between the base class and the


derived class

Create a derived class from a given base class

Understand how access modifiers work with inheritance


types

Compare base and derived classes

Define Liskov’s Substitution Principle


What is Inheritance?

Defining Inheritance
Imagine you want to create two C++ classes, Person and Superhero. These
respective classes might look something like this:

.guides/img/inheritance/CppNoInheritance

There are some similarities between the Person class and the Superhero
class. If the Person class already exists, it would be helpful to “borrow”
from the Person class so you only have to create the new attributes and
functions for the Superhero class. This situation describes inheritance —
one class copies the attributes and functions from another class.

Inheritance Syntax
In the IDE on the left, the Person class is already defined. To create the
Superhero class that inherits from the Person class, add the following code
at the end of the class definitions. Notice how the Superhero class definition
contains a colon : followed by public and then Person. This is how you
indicate to C++ that the Superhero class inherits from the Person class. You
can also say that Person is the base class and Superhero is the derived
class. A base class in C++ is also referred to as a superclass or parent class
while a derived class is also referred to as a subclass or child class. All of
these terms can be used interchangeably.
//add class definitions below this line

class Superhero : public Person {

};

//add class definitions above this line

Now declare an instance of the Superhero class and print the value of the
name and age attributes using their getter functions.

//add code below this line

Superhero s;
cout << s.GetName() << endl;
cout << s.GetAge() << endl;

//add code above this line

What does the output of the program above mean?


In C++, reducing memory usage is important and initializing values to
variables requires memory. Uninitialized variables do not get assigned
specified values automatically. Thus, when printing the value of
uninitialized variables, you might get random and unexpected output. The
output is considered to be junk data that are left over at the variables’
memory location.
challenge

Try these variations:


Call SetName on s with "Peter Parker" as the argument.
Call SetOccupation on s with "Student" as the argument.
Print and call GetOccupation on s.
Call SayHello on s.

Solution

//add code below this line

Superhero s;
s.SetName("Peter Parker");
s.SetOccupation("Student");
cout << s.GetOccupation() << endl;
s.SayHello();

//add code above this line

Accessibility of Inheritance
C++ places some rules about how inheritance works. Depending on the
access modifier of the specified superclass, the subclass may or may not
inherit certain class functions or attributes. Here is a list showcasing each
access modifier and its effect on the subclass.

“public inheritance makes public members of the base class public in


the derived class, and the protected members of the base class remain
protected in the derived class.”
“protected inheritance makes the public and protected members of the
base class protected in the derived class.”
“private inheritance makes the public and protected members of the
base class private in the derived class.”

Source: https://www.programiz.com/cpp-programming/public-protected-
private-inheritance

The list above can be represented using the chart below:


.guides/img/inheritance/InheritanceChart

Source: https://www.bogotobogo.com/cplusplus/private_inheritance.php

Notice how in each case, the derived class never inherits any private
members from the base class. Public inheritance causes the derived class to
inherit the members as is. Protected inheritance causes the derived class to
inherit all public and protected members as protected only. And private
inheritance causes all inherited members to be private only.

You can see how restrictive protected and private inheritance is, which is
why they are rarely used. For this module, we will be using mainly public
inheritance when creating derived classes.
Effects of Inheritance Types 1

Access Modifiers Review


Before we can look at the effects of inheritance types, we will need to
review some access modifier vocabulary:

private - private members of a class can only be accessed by other


members within the same class.
protected - protected members of a class can be accessed by other
members within the same class or by a derived class.
public - public members of a class can be accessed by other members
within the same class, by a derived class, or by an external or outside
class.

The table below showcases these access modifiers’ effects.

.guides/img/inheritance/AccessModifierTable

Source: https://www.tutorialspoint.com/cplusplus/cpp_inheritance.htm

Accessing Class Members


In the text editor, the Base class has already been defined. Within this base
class, you’ll see that there is a public function, a protected function, and a
private function. Add the following derived class to your code:
//add class definitions below this line

class Derived : public Base {


public:
void ReturnPublic(string s) {
Public(s_derived); //public function inherited from Base
}

private:
string s_derived;
};

//add class definitions above this line

The derived class Derived has one public function and one private attribute
and it publicly inherits all public and protected members of the base class
Base. This means that it can call and use any functions or attributes of Base
with the exception of anything that is private.

Next, add the following code into the main function:

//add code below this line

string s_main;
Derived dc;
dc.ReturnPublic(s_main);

//add code above this line

In main, a string s_main and a Derived object dc are created. Then


ReturnPublic() is called on dc with s_main as the parameter. ReturnPublic
is a public member function of the Derived class which takes a string as a
parameter and calls the Public member function of the Base class on
s_derived. The entire process sounds very complicated but can be
explained visually in the flowchart below.
.guides/img/inheritance/FlowChart1

The reason why main is able to call ReturnPublic is due to the fact that
ReturnPublic is a public member function within Derived.

challenge

Try this variation:


Revise Derived to look like:

class Derived : public Base {


protected:
void ReturnPublic(string s) {
Public(s_derived);
}

private:
string s_derived;
};

When the ReturnPublic member function of Derived is protected, main is


no longer able to access it. Remember, external classes can only access
public members of other classes, unless it is a derived class. Derived
classes can access protected members in addition to public ones.
Next, let’s change Derived and main to look like this:

//add class definitions below this line

class Derived : public Base {


public:
void ReturnPublic(string s) {
Public(s_derived); //public function inherited from Base
}

void ReturnProtected(string s) {
Protected(s_derived); //protected function inherited from
Base
}

private:
string s_derived;
};

//add class definitions above this line

//add code below this line

string s_main;
Derived dc;
dc.ReturnProtected(s_main);
dc.Public(s_main);

//add code above this line

Notice how main can call Public and also ReturnProtected from Derived
because those functions are public. Additionally, Derived can call the
protected function Protected in ReturnProtected from Base because
Derived is a derived class of Base.
.guides/img/inheritance/FlowChart2
Effects of Inheritance Types 2

How Inheritance Works


Now that you’re more comfortable with access modifiers, let’s take a look at
how inheritance types affect derived classes. Make sure your Derived and
main code look like what’s below. Note that Derived now inherits from Base
through protected inheritance instead of public.

//add class definitions below this line

class Derived : protected Base {


public:
void ReturnPublic(string s) {
Public(s_derived);
}

void ReturnProtected(string s) {
Protected(s_derived);
}

private:
string s_derived;
};

//add class definitions above this line

//add code below this line

string s_main;
Derived dc;
dc.ReturnProtected(s_main);
dc.Public(s_main);

//add code above this line

You’ll notice that an error is produced saying that ‘Base’ is not an


accessible base of ‘Derived’. This occurs because when a derived class
inherits from a base class through protected inheritance, all public and
protected members of the base class become protected in the derived class.
This means that the Public function within Derived was inherited as a
protected function and is therefore no longer accessible within main.

On the other hand, ReturnProtected is still a public function within


Derived, which allows main to access it even though it calls the protected
function Protected from Base. Comment out the command
dc.Public(s_main); and run the code again to see the result.

Though not explicitly shown, Derived can be represented like this:

class Derived : protected Base {


public:
void ReturnPublic(string s) {
Public(s_derived);
}

void ReturnProtected(string s) {
Protected(s_derived);
}

/*protected:
void Public(string s) { (inherited as protected from Base)
s = "public";
cout << s << endl;
}

void Protected(string s) { (inherited as protected from


Base)
s = "protected";
cout << s << endl;
}*/

private:
string s_derived;
};

If you ever get confused with inheritance types, you can always
imaginatively rewrite all of the functions that were inherited and label
them appropriately to help you visualize the derived class better. Here are
some more examples:
class Base {
public:
int x;

protected:
int y;

private:
int z;
};

class Derived : public Base {


//public:
//int x;

//protected:
//int y;
};

class Base {
public:
int x;

protected:
int y;

private:
int z;
};

class Derived : protected Base {


//protected:
//int x;
//int y;
};
class Base {
public:
int x;

protected:
int y;

private:
int z;
};

class Derived : private Base {


//private:
//int x;
//int y;
};

Note that private members are never inherited. Also, the examples are
provided to help you visualize what the derived classes look like after
inheritance. If you were to actually add the member attributes into Derived
without comments, those attributes will count as being part of the Derived
class instead of being inherited from the Base class.
Inheriting the Constructor

How are Constructors Inherited?


Unlike functions and attributes, the constructor that is inherited by the
derived class needs to get linked or associated with that of the base class. To
connect the derived constructor to the base constructor, follow this syntax:

Derived class name


Parentheses ()
Parameters with specified data types within parentheses
Colon :
Base class name
Parentheses ()
Parameters of derived class as arguments in parentheses
Any additional commands in curly braces {} or leave them empty

Sample Code:
Constructor2(Param p1, Param p2) : Constructor1(p1, p2) {}

Add the following code to the class definitions field:

//add class definitions below this line

class Superhero : public Person {


public:
Superhero(string n2, int a2) : Person(n2, a2) {}
};

//add class definitions above this line

And the following to main:

//add code below this line

Superhero s("Spider-Man", 16);


s.ReturnPerson();

//add code above this line


By associating the derived constructor with the base constructor, C++ is
able to pass the parameters specified in the derived constructor as
arguments of the base constructor. In the code above, the arguments
Spider-Man and 16 are passed to the Superhero constructor and then
transferred over to the Person constructor where they get assigned to name
and age respectively. Then, the ReturnPerson function is used to print name
which is now Spider-Man and age which is now 16.
Comparing Base & Derived Classes

Determining a Derived Class’s Base Class


How do you determine if a derived class actually belongs to a base class?
One common way to determine this is to use the is_base_of<Base,
Derived>::value function. Just substitute Base with the name of the base
class and Derived with the name of the derived class.

//add code below this line

cout << boolalpha;


cout << "B is derived from A: " << is_base_of<A, B>::value <<
endl;
cout << "C is derived from B: " << is_base_of<B, C>::value <<
endl;
cout << "A is derived from C: " << is_base_of<C, A>::value <<
endl;

//add code above this line

Here is an example:

//add code below this line

cout << boolalpha;


cout << "Superhero is derived from Person: " <<
is_base_of<Person, Superhero>::value << endl;
cout << "Animal is derived from Superhero: " <<
is_base_of<Superhero, Animal>::value << endl;
cout << "Person is derived from Animal: " <<
is_base_of<Animal, Person>::value << endl;

//add code above this line


challenge

Try this variation:


Add the following to main:

cout << "Person is derived from Superhero: ";


cout << is_base_of<Superhero, Person>::value << endl;

You’ll notice that the function returns true if the derived class inherits from
the base class and false when that is not the case.

Determining an Object’s Base Class


Unfortunately, C++ has no built-in function to determine if an object is from
a class that inherits from another class. Instead, use
typeid(<object_name>).name() to try and extract the object’s type, and then
use the is_base_of<Base, Derived>::value to see if that object’s class is
derived from another specified class. Replace <object_name> with the name
of the object.

Remove all existing code in main and add the following:

//add code below this line

Superhero s;
cout << "s is of type: " << typeid(s).name() << endl;

//add code above this line

Your output may look something like s is of type: 9Superhero. The 9 is


just a number that is produced by the compiler, which can be ignored.
Once you determine the object’s class, you can then compare that class to
another class to see if it is a derived class.
//add code below this line

Superhero s;
cout << "s is of type: " << typeid(s).name() << endl;
cout << boolalpha;
cout << "Superhero is derived from Person: ";
cout << is_base_of<Person, Superhero>::value << endl;

//add code above this line

The functions provided above can help you determine an object’s class and
compare it with another known class. There is unfortunately no function to
determine an object’s base class directly.
Substitution Principle

Substitution Principle
When one class inherits from another, C++ considers them to be related.
They may contain different data types, but C++ allows a derived class to be
used in place of the base class. This is called Liskov’s Substitution
Principle. In the text editor you’ll notice that Superhero inherits from
Person, but Animal does not. All classes have the Greeting function which
prints a statement specific to the class.

//add class definitions below this line

class Person {
public:
void Greeting() {
cout << "I'm a Person" << endl;
}
};

class Superhero : public Person {


public:
void Greeting() {
cout << "I'm a Superhero" << endl;
}
};

class Animal {
public:
void Greeting() {
cout << "I'm an Animal" << endl;
}
};

//add class definitions above this line

According to the Substitution Principle, an object of Superhero can be used


in a situation that expects an object of Person. Add the Substitution
function below which explicitly requires a parameter of a Person object.
//add function definitions below this line

void Substitution(Person p) {
p.Greeting();
}

//add function definitions above this line

Instantiate an object of Superhero and pass it to the Substitution function.


Even though the object s has the wrong data type, the code should still
work due to the Substitution Principle. Because Superhero is derived from
Person, object s can be used in place of an object of type Person. Run the
code to verify the output.

//add code below this line

Superhero s;
Substitution(s);

//add code above this line

challenge

Try this variation:


Revise main to:

Animal a;
Substitution(a);

Why did this produce an error?


The Animal class is not derived from Person, therefore the Substitution
Principle no longer applies.

The Substitution Principle is a One-Way


Relationship
Let’s revise the Substitution function and main to look like below:
//add function definitions below this line

void Substitution(Superhero s) {
s.Greeting();
}

//add function definitions above this line

//add code below this line

Person p;
Substitution(p);

//add code above this line

The code above produces an error stating that the object p cannot be
converted to a Superhero object. Kind of like how a square is considered to
be a rectangle, but a rectangle is not considered to be a square, inheritance
works the same way. A Superhero object is considered to be a Person object,
but a Person object is not considered to be Superhero object.

Inheritance Can Be Extended


Inheritance can be extended, which means that a derived class can inherit
attributes of another derived class. Revise the class definitions to look like
below:
//add class definitions below this line

class Person {
public:
void Greeting() {
cout << "I'm a Person" << endl;
}
};

class Hero : public Person {


public:
void Greeting() {
cout << "I'm a Hero" << endl;
}
};

class Superhero: public Hero {


public:
void Greeting() {
cout << "I'm a Superhero" << endl;
}
};

//add class definitions above this line

You’ll notice that we have an intermediate class called Hero which is a


derived class of Person. The Superhero class is then derived from the Hero
class. When there are multiple levels of inheritance, the immediate upper
class is considered to be a direct base class and all higher classes are
considered to be indirect base classes. This means that Hero is a direct base
class of Superhero while Person is an indirect base class of Superhero.
Superhero is still considered to be a derived class of both Hero and Person.

See what happens when you you revise the Substitution function and main
to look like below:

//add function definitions below this line

void Substitution(Person p) {
p.Greeting();
}

//add function definitions above this line


//add code below this line

Superhero s;
Substitution(s);
Hero h;
Substitution(h);

//add code above this line

Whether the object is of class Superhero or Hero, the Substitution function


still works because both are derived classes of Person.
Learning Objectives: Extending &
Overriding

Define the terms extending and overriding

Extend the derived class with a new function

Override functions from the base class with new


functionality
Extending a Class

Extending the Derived Class


The idea of inheritance is to borrow from a base class and then add on
functionality. Up until now, we have talked about borrowing from a base
class but have not gone into detail about adding additional functionality to
the derived class. The process of adding functionality to a derived class is
known as either extending or overriding. Extending a class means that new
attributes and functions are given to the derived class. Let’s continue
working with our Person and Superhero classes.

.guides/img/inheritance/CppNoInheritance

The code below will first associate the derived class constructor with the
base class constructor. However, we want to add an additional attribute as
a parameter to the derived class constructor. Doing so will extend the
derived class because objects created will have 4 parameter attributes
instead of 3. Additional getter and setter functions are also added to extend
the derived class even further.
//add class definitions below this line

class Superhero : public Person {


public:
Superhero(string n, int a, string o, string s) : Person(n,
a, o) {
secret_identity = s;
}

string GetSecretIdentity() {
return secret_identity;
}

void SetSecretIdentity(string new_secret_identity) {


secret_identity = new_secret_identity;
}

private:
string secret_identity;
};

//add class definitions above this line

In main, instantiate a Superhero object and print out each of the attributes.
You should see the three attributes from the Person class as well as the new
attribute secret_identity.

//add code below this line

Superhero hero("Spider-Man", 16, "student", "Peter Parker");


cout << hero.GetName() << endl;
cout << hero.GetAge() << endl;
cout << hero.GetOccupation() << endl;
cout << hero.GetSecretIdentity() << endl;

//add code above this line

Inheritance Is a One-Way Street


Inheritance shares attributes and functions from the base class to the
derived class. When a derived class is extended, it cannot share the new
additions with its base class. For example, in the code above, the Superhero
class has access to the attributes name, age, and occupation, but Person does
not have access to secret_identity.
challenge

Try this variation:


Rewrite the Superhero class so that it extends the Person class by
adding the string attribute nemesis. The constructor will also
include nemesis as the last parameter with Doc Octopus as its
argument. Remember to include the relevant getter and setter
functions too!
Solution

//add class definitions below this line

class Superhero : public Person {


public:
Superhero(string n, int a, string o, string s, string
ne) : Person(n, a, o) {
secret_identity = s;
nemesis = ne;
}

string GetSecretIdentity() {
return secret_identity;
}

void SetSecretIdentity(string new_secret_identity) {


secret_identity = new_secret_identity;
}

string GetNemesis() {
return nemesis;
}

void SetNemesis(string new_nemesis) {


nemesis = new_nemesis;
}

private:
string secret_identity;
string nemesis;
};

//add class definitions above this line

int main() {
//add code below this line

Superhero hero("Spider-Man", 16, "student", "Peter


Parker", "Doc Octopus");
cout << hero.GetName() << endl;
cout << hero.GetAge() << endl;
cout << hero.GetOccupation() << endl;
cout << hero.GetSecretIdentity() << endl;
cout << hero.GetNemesis() << endl;

//add code above this line

return 0;

Extending a Class by Adding Unique Functions


Another way to extend a class is to create new functions that are unique to
the derived class (besides getter and setter functions). Currently, the
function SayHello will print the superhero’s name, but it will not print their
secret identity. Create the function RevealSecretIdentity to print a greeting
that reveals SecretIdentity.
//add class definitions below this line

class Superhero : public Person {


public:
Superhero(string n, int a, string o, string s, string ne) :
Person(n, a, o) {
secret_identity = s;
nemesis = ne;
}

string GetSecretIdentity() {
return secret_identity;
}

void SetSecretIdentity(string new_secret_identity) {


secret_identity = new_secret_identity;
}

string GetNemesis() {
return nemesis;
}

void SetNemesis(string new_nemesis) {


nemesis = new_nemesis;
}

void RevealSecretIdentity() {
cout << "My real name is " << secret_identity << '.' <<
endl;
}

private:
string secret_identity;
string nemesis;
};

//add class definitions above this line

Now test out the newly added function.

//add code below this line

Superhero hero("Spider-Man", 16, "student", "Peter Parker",


"Doc Octopus");
hero.RevealSecretIdentity();

//add code above this line


challenge

Try this variation:


Create the function SayNemesis that prints the string
My nemesis is Doc Octopus., then call it on hero in main.
Solution

//add class definitions below this line

class Superhero : public Person {


public:
Superhero(string n, int a, string o, string s, string
ne) : Person(n, a, o) {
secret_identity = s;
nemesis = ne;
}

string GetSecretIdentity() {
return secret_identity;
}

void SetSecretIdentity(string new_secret_identity) {


secret_identity = new_secret_identity;
}

string GetNemesis() {
return nemesis;
}

void SetNemesis(string new_nemesis) {


nemesis = new_nemesis;
}

void RevealSecretIdentity() {
cout << "My real name is " << secret_identity << '.'
<< endl;
}

void SayNemesis() {
cout << "My nemesis is " << nemesis << '.' << endl;
}

private:
string secret_identity;
string nemesis;
};

//add class definitions above this line

int main() {

//add code below this line

Superhero hero("Spider-Man", 16, "student", "Peter


Parker", "Doc Octopus");
hero.SayNemesis();

//add code above this line

return 0;

}
Function Overriding

Overriding a Function
Extending a class means adding new attributes or functions to the derived
class. Another way to add new functionality to a derived class is through
function overriding. Overriding a function means to inherit a function
from the base class, keep its name, but change the contents of the function.

Extend the Superhero class by overriding the SayHello function. Remember,


the name attribute is part of the base class and it is private, so you need to
use the GetName function to access this attribute.

//add class definitions below this line

void SayHello() {
cout << "My name is " << GetName() << ", and criminals
fear me." << endl;
}

//add class definitions above this line

Instantiate a Superhero object and call the SayHello function on it.

//add code below this line

Superhero hero("Storm", 30, "Queen of Wakanda", "Ororo


Munroe", "Shadow King");
hero.SayHello();

//add code above this line

Differentiating Overriding and Extending


The difference between extending and overriding can be slight. Both
approaches are used to make a derived class unique from the base class.
However, overriding deals with changing a pre-existing function from the
base class, while extending deals with adding new functions and
attributes.
challenge

Try this variation:


Add and override the SayAge function in the Superhero class so that
it prints the string, Age is just a number., then call it on hero in
the main function.
Solution

void SayAge() {
cout << "Age is just a number." << endl;
}

Superhero hero("Storm", 30, "Queen of Wakanda", "Ororo


Munroe", "Shadow King");
hero.SayAge();

What Happens to the Overridden Function?


If you can override a function from the base class, what happens to its
original function? C++ defaults to the instance or object type. So
hero.SayHello() will always use the function from the derived Superhero
class. But that does not mean you cannot call SayHello from the base Person
class. To call the original base class function, you can use
hero.Person::SayAge() where hero represents the derived class object,
Person represents the base class, and SayAge represents the base class
function. The :: is called the scope resolution operator and it is used to
direct C++ to look for the function SayAge inside the Person class. Make sure
you have the following class definitions in your code.
//add class definitions below this line

void SayHello() {
cout << "My name is " << GetName() << ", and criminals
fear me." << endl;
}

void SayAge() {
cout << "Age is just a number." << endl;
}

//add class definitions above this line

Then run the following commands in main to see the result.

//add code below this line

Superhero hero("Storm", 30, "Queen of Wakanda", "Ororo


Munroe", "Shadow King");
hero.SayHello();
hero.Person::SayHello();
hero.SayAge();
hero.Person::SayAge();

//add code above this line

Note how in the code above, using the scope resolution operator causes the
base class function to be called while not using it causes the derived class
function to be called.
challenge

Try this variation:


Modify the following code in the Person class:

void SayHello() {
cout << "Hello, my name is " << name << '.' << endl;
}

void SayAge() {
cout << "I am " << age << " years old." << endl;
}

to

virtual void SayHello() final {


cout << "Hello, my name is " << name << '.' << endl;
}

virtual void SayAge() final {


cout << "I am " << age << " years old." << endl;
}

Why is there an error?


To prevent a derived class from overriding a base class function, you
can use the key terms virtual and final. virtual goes in front of the
function declaration name while final goes behind. Adding these key
terms keeps you from overriding the functions in the Superhero class.
That is why you see the error. You’ll learn more about these key terms
in a future module.
Learning Objectives: Multilevel
Inheritance
Define multilevel inheritance

Create multilevel inheritance from a class with a base


class

Extend a class and override a function within multilevel


inheritance
Multiple Inheritance

Multiple Inheritance
Multiple inheritance is a condition where a class inherits from more than
one base class. C++ allows multiple inheritance for both associated and
unassociated base classes; however, for this particular section, we will only
go over multiple inheritance with associated base classes, meaning one
base class is derived from another base class.

Multilevel Inheritance
Multiple inheritance with associated base classes is called multilevel
inheritance. This is a condition where a class inherits from more than one
base class, but each base class is associated with each other. The image
below shows ClassC inheriting from ClassB, which in turn inherits from
ClassA. This is an example of multilevel inheritance.

.guides/img/inheritance/MultiLevelInheritance

The classes Carnivore and Dinosaur are already defined. Carnivore is the
base class for Dinosaur. Create the Tyrannosaurus class which is a derived
class of Dinosaur. The constructor for Tyrannosaurus takes a string and two
doubles and gets associated with the constructor from the Dinosaur class.

//add class definitions below this line

class Tyrannosaurus : public Dinosaur {


public:
Tyrannosaurus(string d, double s, double w) : Dinosaur(d,
s, w) {}
};

//add class definitions above this line


Instantiate a Tyrannosaurus object with the appropriate arguments. This t-
rex tiny is 12 meters tall, weighs 14 metric tons, and eats whatever it
wants. Print the size attribute to make sure inheritance is working as
expected.

//add code below this line

Tyrannosaurus tiny("whatever it wants", 12, 14);


cout << tiny.GetSize() << endl;

//add code above this line

challenge

Try these variations:


Print the weight attribute with cout << tiny.GetWeight() << endl;
Print the diet attribute with cout << tiny.GetDiet() << endl;
Extending & Overriding Functions

Extending a Class within Multilevel


Inheritance
Multilevel inheritance works just like single inheritance except there are
more than one derived class. Add the following code as class definitions in
the text editor.

//add class definitions below this line

class ClassC : public ClassB {


public:
void Bonjour() {
cout << "Bonjour" << endl;
}
};

//add class definitions above this line

Instantiate a ClassC object to call the Bonjour function. Then use the scope
resolution operator : to invoke the Hello function from both ClassB and
ClassA.

//add code below this line

ClassC c;
c.Bonjour();
c.ClassB::Hello();
c.ClassA::Hello();

//add code above this line


challenge

Try this variation:


Extend ClassC with the function AuRevoir that prints Au revoir.
Then call this function in main.
Solution

//add class definitions below this line

class ClassC : public ClassB {


public:
void Bonjour() {
cout << "Bonjour" << endl;
}

void AuRevoir() {
cout << "Au revoir" << endl;
}
};

//add class definitions above this line

int main() {

//add code below this line

ClassC c;
c.AuRevoir();

//add code above this line

return 0;

Overriding a Function within Multilevel


Inheritance
Like extending a class, overriding a function works the same in multilevel
inheritance as it does in single inheritance. Change ClassC so that it
overrides the Hello function.
//add class definitions below this line

class ClassC : public ClassB {


public:
void Hello() {
cout << "Hello from Class C" << endl;
}
};

//add class definitions above this line

Now replace the call to Bonjour with a call to Hello.

//add code below this line

ClassC c;
c.Hello();
c.ClassB::Hello();
c.ClassA::Hello();

//add code above this line

Notice how calling the Hello function automatically defaults to the function
within the object’s specified class. If you want to call the same function as
specified from within another base class, simply use the scope resolution
operator : as shown above.
Lab 1

Lab 1 - Making the Base Class and Derived Class


In this lab, we will be creating a base class called Line. Line has only one
attribute, int length, which is used in the class function DrawLine. DrawLine
takes an integer parameter and outputs * as many times as specified in
length. To retrieve length, we also have the getter function GetLength. Line
does not have a setter function.

//add class definitions below this line

class Line {
public:
Line(int l) {
length = l;
}

int GetLength() {
return length;
}

void DrawLine() {
for (int i = 0; i < length; i++) {
cout << '*';
}
cout << endl;
}

private:
int length;
};

//add class definitions above this line

To test our Line class, create its object and then call the DrawLine function
on it in main.
//add code below this line

Line line(10);
line.DrawLine();

//add code above this line

The output is a line drawn with 10 * symbols. Next, we will create a


derived class, Box, that inherits from Line.

Box has one attribute, int width, which will present the width of the Box
object. The Box constructor takes two parameters, one of which is presented
by width and the other is presented by length which is inherited from the
Line constructor. Box has two class functions, the getter GetWidth and
DrawBox. Notice how inheritance enables us to borrow functions and
attributes from the base class to further extend the derived class.

DrawBox utilizes the width attribute to tell the system how many times to
call DrawLine. The end result is a draw of a “box” that is created from
multiple “lines”.
//add class definitions below this line

class Line {
public:
Line(int l) {
length = l;
}

int GetLength() {
return length;
}

void DrawLine() {
for (int i = 0; i < length; i++) {
cout << '*';
}
cout << endl;
}

private:
int length;
};

class Box : public Line {


public:
Box(int l, int w) : Line(l) {
width = w;
}

int GetWidth() {
return width;
}

void DrawBox() {
for (int i = 0; i < width; i++) {
DrawLine();
}
}

private:
int width;
};

//add class definitions above this line

Run the code below in main to see the output.


//add code below this line

Box box(10, 10);


box.DrawBox();

//add code above this line

challenge

Try these variations:


Change Box box(10, 10); to Box box(3, 6);.
Change Box box(3, 6); to Box box(8, 4);.
Lab 2

Lab 2 - Applying Multilevel Inheritance


Previously in Lab 1, we created the base class Line and the derived class
Box. In this lab, we will create another derived class that inherits from Box
directly and Line indirectly. This concept of a derived class inheriting from
another derived class is called multilevel inheritance.

Given Code

#include <iostream>
using namespace std;

//add class definitions below this line

class Line {
public:
Line(int l) {
length = l;
}

int GetLength() {
return length;
}

void DrawLine() {
for (int i = 0; i < length; i++) {
cout << '*';
}
cout << endl;
}

private:
int length;
};

class Box : public Line {


public:
Box(int l, int w) : Line(l) {
width = w;
}
int GetWidth() {
return width;
}

void DrawBox() {
for (int i = 0; i < width; i++) {
DrawLine();
}
}

private:
int width;
};

//add class definitions above this line

int main() {

//add code below this line

//add code above this line

return 0;

Our new derived class is called Pattern. This class builds off of Box and Line
by utilizing their getter functions GetLength and GetWidth. First we need to
build the Pattern constructor which inherits the Box constructor exactly.
Then we will create a new function called DrawPattern that will output a
modified “box” with a pattern. Note that Pattern does not have any private
members. It is simply an extension of the Box class.

//add class definitions below this line

class Line {
public:
Line(int l) {
length = l;
}

int GetLength() {
return length;
}

void DrawLine() {
for (int i = 0; i < length; i++) {
cout << '*';
}
cout << endl;
}

private:
int length;
};

class Box : public Line {


public:
Box(int l, int w) : Line(l) {
width = w;
}

int GetWidth() {
return width;
}

void DrawBox() {
for (int i = 0; i < width; i++) {
DrawLine();
}
}

private:
int width;
};

class Pattern : public Box {


public:
Pattern(int l, int w) : Box(l, w) {}

void DrawPattern() {
for (int i = 0; i < GetLength(); i++) {
if (i % 2 == 0) {
for (int j = 0; j < GetWidth(); j++) {
if ( (j % 2 == 0) ) {
cout << '*';
}
else {
cout << ' ';
}
}
cout << endl;
}
if (i % 2 == 1) {
for (int j = 0; j < GetWidth(); j++) {
if ( (j % 2 == 0) ) {
cout << ' ';
}
else {
cout << '*';
}
}
cout << endl;
}
}
}
};

//add class definitions above this line

Rather than create a “box” of “lines”, a “pattern” is created by specifying


certain indices to output * while others output a white space (' '). In
particular, this is the pattern (note the pattern starts at index 0 for both
rows and columns):

even row + even column = *


even row + odd column = ' '
odd row +even column = ' '
odd row + odd column = *

Try the following code in main to see the output.

//add code below this line

Pattern pattern(10, 10);


pattern.DrawPattern();

//add code above this line


challenge

Try these variations:


Change Pattern pattern(10, 10); to Pattern pattern(3, 6);.
Change Pattern pattern(3, 6); to Pattern pattern(8, 20);.
Lab Challenge

Problem

In the IDE to the left, the class MP3 is already defined. Complete the class
Podcast that inherits from MP3. This class should do the following things:
* Inherit the constructor such that Podcast has the following attributes:
* title - a string that is the title of the episode
* length - an integer that has the length of the podcast in seconds
* genre - a string that is the genre of the podcast
* name - a string that is the name of the podcast
* date - a string that represents when the podcast was released to the public
* DO NOT EDIT the specified code or you might not receive credit for your
work!

Hint: Connecting the Constructors

Note that a few of the attributes are present in both the MP3 and Podcast
classes. To connect their constructors, you can use the same parameter
values for the attributes that are the same, then use different parameter
values for the attributes that are different. Finally, set the attributes to the
parameters appropriately for the ones that are different. For example:

Podcast(string t, int l, string g, string n, string d) : MP3(t,


l, g, n, d) {
name = n;
date = d;
}

Given Code

#include <iostream>
using namespace std;

//DO NOT EDIT code below this line

class MP3 {
public:
MP3(string t, int l, string g, string al, string ar) {
title = t;
album = al;
length = l;
genre = g;
artist = ar;
}

string GetTitle() {
return title;
}

void SetTitle(string new_title) {


title = new_title;
}

int GetLength() {
return length;
}

void SetLength(int new_length) {


length = new_length;
}

string GetGenre() {
return genre;
}

void SetGenre(string new_genre) {


genre = new_genre;
}

string GetAlbum() {
return album;
}

void SetAlbum(string new_album) {


album = new_album;
}

string GetArtist() {
return artist;
}

void SetArtist(string new_artist) {


artist = new_artist;
}

private:
string title;
int length;
string genre;
string album;
string artist;
};

//DO NOT EDIT code above this line

//add class definitions below this line

//DO NOT EDIT///////////////////


class Podcast : public MP3 { //
////////////////////////////////

//add class definitions above this line

int main() {

//DO NOT EDIT code below this line

Podcast p("Hollywood Black List", 1460, "economics", "Planet


Money", "10 July 2020");
p.DisplayTitle();
p.DisplayLength();
p.DisplayGenre();
p.DisplayName();
p.DisplayDate();

//DO NOT EDIT code above this line

return 0;

Expected Output

The title is Hollywood Black List


The length is 1460
The genre is economics
The name is Planet Money
The date is 10 July 2020
Testing Your Code
Use the button below to test your code before submitting it for evaluation.
Learning Objectives:
Polymorphism
Define polymorphism

Explain how function overriding is an example of


polymorphism

Overload a function

Override a function

Use an abstract function as a form of polymorphism


Function Overriding

What is Polymorphism?
Polymorphism is a concept in object-oriented programming in which a
single interface takes different forms (polymorphism means “many
forms”). Often this means similar operations are grouped together with the
same name. However, these operations with the same name will produce
different results. You have already encountered a few examples of
polymorphism. Enter the following code into the IDE.

//add code below this line

int a = 5;
int b = 10;
cout << (a + b) << endl;

string c = "5";
string d = "10";
cout << (c + d) << endl;

bool e = true;
bool f = false;
cout << (e + f) << endl;

//add code above this line

Notice how the plus operator (+) can add together two numbers,
concatenate two strings, and add two booleans. You have a single interface
(the plus operator) taking different forms — one that works with integers,
another that works with strings, and even one that works with booleans.
This is an example of polymorphism.

Operator Overloading
Because the plus operator can work with different forms, we can say that it
is overloaded. C++ overloads this operator by default. However, a user
cannot manually overload an operator.
challenge

Try these variations:


Change your code to look like this:

//add code below this line

int a = 5;
string b = "true";
cout << (a + b) << endl;

//add code above this line

Why is there an error?


Polymorphism allows C++ to use the plus operator with different data
types, but that does not mean that the plus operator can be used with
all data types. The example above causes an error message because the
plus operator cannot be used with an integer and a string. There are
limits to polymorphism.

Change string b = "true"; in the code above to bool b = true;.

Why does the code above work?


Remember that a boolean value of true is equivalent to an integer
value of 1. This is why it is possible to add boolean and integer values
together.

Function Overriding
Function overriding is another example of polymorphism that you have
already seen. Overriding a function means that you have two functions
with the same name, but they perform different tasks. Again you see a
single interface (the function name) being used with different forms (the
base class and the derived class). Create the following classes.
//add class definitions below this line

class Alpha {
public:
void Show() {
cout << "I am from class Alpha" << endl;
}
};

class Bravo: public Alpha {


public:
void Show() {
cout << "I am from class Bravo" << endl;
}
};

//add class definitions above this line

Then instantiate an Alpha object and call the Show function.

//add code below this line

Alpha test_object;
test_object.Show();

//add code above this line

As expected, the script prints I am from class Alpha. Now change the line
of code in which you instantiate the object test_object to a Bravo object
like below. Make no other changes and run the code again.

Bravo test_object;

Now the script prints I am from class Bravo. The function call did not
change, but the output did. A single interface (the Show function) works
with multiple forms (the Alpha and Bravo data types). This is why function
overriding is an example of polymorphism.

challenge

Try this variation:


Create and overload the function Hello that prints Hello from
Alpha and Hello from Bravo to the Alpha and Bravo classes
respectively. Then test the function on both class types by calling it
on their respective objects.

Solution

//add class definitions below this line

class Alpha {
public:
void Show() {
cout << "I am from class Alpha" << endl;
}

void Hello() {
cout << "Hello from Alpha" << endl;
}
};

class Bravo: public Alpha {


public:
void Show() {
cout << "I am from class Bravo" << endl;
}

void Hello() {
cout << "Hello from Bravo" << endl;
}
};

//add class definitions above this line

int main() {

//add code below this line

Alpha test_object; //Then test with Bravo test_object


test_object.Hello();

//add code above this line

return 0;

}
Function Overloading

Function Overloading
Function overloading is another example of polymorphism. Function
overloading occurs when you have a single function name that can take
different sets of parameters. Imagine you want to write the function Sum
that can sum up to three numbers. The math involved with three
parameters is slightly different than two parameters, which is different
from 1 parameter, etc. Traditionally, if you declare a function that takes
three parameters but only pass two, C++ will throw an error message.
Instead, let’s create a class that has two Sum functions; one with two
parameters and another with three parameters.

//add class definitions below this line

class TestClass {
public:
int Sum(int n1, int n2, int n3) {
return n1 + n2 + n3;
}

int Sum(int n1, int n2) {


return n1 + n2;
}
};

//add class definitions above this line

Create an object of type TestClass and call both versions of the Sum
function. Be sure you are passing three arguments for one function and
two arguments for the other.

//add code below this line

TestClass tc;
cout << tc.Sum(1, 2, 3) << endl;
cout << tc.Sum(1, 2) << endl;

//add code above this line


C++ looks at the number and types of arguments and, as long there is a
matching function definition, runs the code without an error. Defining the
same function with different sets of arguments is called overloading. It is
also an example of polymorphism.

challenge

Try this variation:


Continue to overload the Sum function such that it can take up to
five numbers as parameters (which means 4 functions total). Be
sure to test all possible function calls in main.

Solution
//add class definitions below this line

class TestClass {
public:
int Sum(int n1, int n2, int n3, int n4, int n5) {
return n1 + n2 + n3 + n4 + n5;
}

int Sum(int n1, int n2, int n3, int n4) {


return n1 + n2 + n3 + n4;
}

int Sum(int n1, int n2, int n3) {


return n1 + n2 + n3;
}

int Sum(int n1, int n2) {


return n1 + n2;
}
};

//add class definitions above this line

int main() {

//add code below this line

TestClass tc;
cout << tc.Sum(1, 2, 3, 4, 5) << endl;
cout << tc.Sum(1, 2, 3, 4) << endl;
cout << tc.Sum(1, 2, 3) << endl;
cout << tc.Sum(1, 2) << endl;

//add code above this line

return 0;

Overloading the Constructor


C++ will also allow you to overload the constructor so that objects are
instantiated in a variety of ways. The Person class has a default constructor
(no arguments) and a constructor with three arguments.

//add class definitions below this line

class Person {
public:
Person() {}

Person(string na, int nu, string s) {


name = na;
number = nu;
street = s;
}

string Info() {
return (name + " lives at " + to_string(number) + ' ' +
street + '.');
}

private:
string name;
int number;
string street;
};

//add class definitions above this line

When you create a Person object with no arguments, the Info function still
works. However, the information that is printed may look jarring since C++
will use left-over “junk” memory data to fill in for variables that are not
initialized. You can also instantiate an object with three arguments. Like
function overloading, constructor overloading is a form of polymorphism.

//add code below this line

Person p1;
Person p2("Calvin", 37, "Main Street");
cout << p1.Info() << endl;
cout << p2.Info() << endl;

//add code above this line

Random Values
Unlike other programming languages, C++ does not automatically initialize
variables that are not initialized by the user. This is done to preserve
memory. Thus, you might get “randomly” generated data for certain
uninitialized variables. Run the code several more times and you’ll notice
different values will be printed.

challenge

Try these variations:


Comment out both of the constructors.

//add class definitions below this line

class Person {
public:
//Person() {}

//Person(string na, int nu, string s) {


//name = na;
//number = nu;
//street = s;
//}

string Info() {
return (name + " lives at " + to_string(number) + " "
+ street + ".");
}

private:
string name;
int number;
string street;
};

//add class definitions above this line

Instantiate a Person object and call the Info function.


//add code below this line

Person p1;
//Person p2("Calvin", 37, "Main Street");
cout << p1.Info() << endl;
//cout << p2.Info() << endl;

//add code above this line

Why does this work?


When you do not declare a constructor, C++ will use the default
constructor and give each of the attributes their default value.

Uncomment only the constructor with three arguments.

//add class definitions below this line

class Person {
public:
//Person() {}

Person(string na, int nu, string s) {


name = na;
number = nu;
street = s;
}

string Info() {
return (name + " lives at " + to_string(number) + " "
+ street + ".");
}

private:
string name;
int number;
string street;
};

//add class definitions above this line

Do not make any changes to the object instantiation in main.

Why is there an error?


C++ automatically uses the default constructor when there are no
constructors defined. If, however, a constructor exists, the object that
gets instantiated must contain the same number of arguments as
specified by that constructor’s parameters. Otherwise, an error will be
produced.
Abstract Functions

Abstract Classes
Another form of polymorphism in C++ involves abstract functions. These
functions, however, require knowledge of abstract classes. So before we
continue the discussion on polymorphism, we need to first talk about
abstract classes.

Concrete Classes
Any class that is not an abstract class is considered to be a concrete class.
You do not need to use a keyword to indicate that a class is concrete.

A defining characteristic of an abstract class is that an abstract class has at


least one abstract, or pure virtual, function. An abstract function is a
function that is defined as being equal to 0 in the base class, but is expected
to be redefined in the derived class.

Abstract (Pure Virtual) Functions


When will there be a need for abstract functions? Abstract functions are
used when the derived classes are expected to use a particular abstract
function from the base class differently. Let’s take a look at a classic
example of the Shape class.

//add class definitions below this line

class Shape {
public:
virtual double Area() = 0;
};

//add class definitions above this line

As seen in the above code, the virtual function Area is defined as being
equal to 0. We do this because we expect classes that are derived from
Shape to have Area functions that behave differently. For example,
calculating the area of a Triangle object is different from calculating the
area of a Rectangle object. Thus, we define Area as an abstract function in
the base class Shape. Note that when you redefine abstract functions in the
derived classes, you do not include the virtual keyword nor assign the
function to 0. Let’s define our classes further.

//add class definitions below this line

class Shape {
public:
virtual double Area() = 0;

double GetBase() {
return base;
}

void SetBase(double new_base) {


base = new_base;
}

double GetHeight() {
return height;
}

void SetHeight(double new_height) {


height = new_height;
}

protected:
double base;
double height;
};

class Triangle : public Shape {


public:
Triangle(double b, double h) {
base = b;
height = h;
}

double Area() {
return base * height / 2;
}
};

class Rectangle : public Shape {


public:
Rectangle(double b, double h) {
base = b;
height = h;
}

double Area() {
return base * height;
}
};

//add class definitions above this line

You can see above that two classes are derived from Shape, the Triangle
class and the Rectangle class. Also notice how Shape contains additional
getters and setters as well as protected attributes. We encapsulate them as
protected in order for our derived classes to access them. This way, we
don’t have to declare additional attributes in Triangle and Rectangle.

Next, let’s test our code in main.

//add code below this line

Triangle t(4, 4);


cout << t.Area() << endl;
Rectangle r(4, 4);
cout << r.Area() << endl;

//add code above this line

As expected, the code returns the correct calculations for the Triangle and
Rectangle objects.
challenge

Try this variation:


Change cout << t.Area() << endl; to cout << t.Shape::Area() <<
endl;
Replace the entire code in main with

//add code below this line

Shape s;

//add code above this line

Why are there errors?


You cannot create an object of an abstract class nor can you call an
abstract function. This is why using encapsulation and inheritance is
important in redefining functions so that they can be used in derived
classes. Because abstract functions get redefined and used differently,
they are considered to be a concept of polymorphism.
Lab 1

Lab 1
This lab will focus on using polymorphism while interacting with a contact
list. There will be a main class Contacts that controls the “view” the user
sees and responds to user input. The contact information (personal and
work) will be an instance of the Information class.

The Contacts Class


This lab is built around the Contacts class, which has four attributes:
* view - This string attribute controls what the user sees. When the value
for view changes, the information changes. There are four different views.
* List view - Shows the list of all of the contacts.
* Information view - Shows the work and personal information for a
particular contact.
* Add view - Add information for a new contact.
* Quit view - Leave a message for the user and then end the program.
* names - Vector of strings that stores the names of each person in the
contact list.
* titles - Vector of strings that stores the titles for each person in the
contact list.
* workPhoneNumbers - Vector of strings that stores the work phone numbers
for each person in the contact list.
* workEmails - Vector of strings that stores the work email addresses for
each person in the contact list.
* personalPhoneNumbers - Vector of strings that stores the personal phone
numbers for each person in the contact list.
* personalEmails - Vector of strings that stores the personal email addresses
for each person in the contact list.

choice - This string attribute represents input from the user and is used
to change view.
index - This integer attribute keeps track of the particular contact whose
information is to be displayed.
length - This integer attribute keeps track of the length of the above
vectors.

To put polymorphism into practice, we are going to create the abstract class
Information. This will have the pure abstract functions DisplayInfo and
AddInfo. The Contacts class inherits from Information, and therefore it
must override the DisplayInfo and AddInfo functions.

//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
void DisplayInfo() {

void AddInfo() {

}
};

//add class definitions above this line

Add the attributes and constructor for the Contacts class. For testing
purposes, set view to "quit". We will change this to a more appropriate
value later on. The other attributes do not need a value when instantiating
the object. Instantiate each vector attribute, set choice to an empty string,
and set index and length to 0. Additionally, add the Display function, which
we will go in more detail later on.

//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "quit";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}

void DisplayInfo() {

void AddInfo() {

void Display() {

private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;
};

//add class definitions above this line

The Display Function


The Display function is designed to be a loop that runs until the user tells
the program to end. The function checks the value of the view attribute and
calls the appropriate function that displays the information for each view.
Since the loop is while (true), be sure to include a break statement
otherwise the loop would never stop (C++ would eventually stop the
program with an error message). Fill out the Display function like below.
void Display() {
while (true) {
if (view==("list")) {
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout << " " << endl;
AddInfo();
}
else if (view==("quit")) {
cout << ("\nClosing the contact list...\n");
break;
}
}
}

Starting the Other Functions


The Display function calls three other functions; DisplayInfo and AddInfo
have already been declared. Trying to test the code would cause your
program to crash as the ShowList function has not yet been defined. Create
another empty function ShowList just as was done with DisplayInfo and
AddInfo. We will come back later and add working code to each function.
However, to get your code to run we must provide a definition for virtual
functions in your base class.

void DisplayInfo() {

void AddInfo() {

void ShowList() {

Testing Your Code


Before moving on to the next part of the script, we want to check that our
code is working. To do that, instantiate a Contacts object and call the
Display function.

//add code below this line

Contacts contacts;
contacts.Display();

//add code above this line

Run your program. Because the view attribute is "quit", the script should
immediately display a message and then stop. Your output should look
something like this.

.guides/img/Polymorphism/output_lab1_updated

Code

Your code should look like this:

#include <iostream>
#include <vector>
using namespace std;

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "quit";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}
void DisplayInfo() {

void AddInfo() {

void ShowList() {

void Display() {
while (true) {
if (view==("list")) {
ShowList();
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout<< " "<<endl;
AddInfo();
}
else if (view==("quit")) {
cout<< ("\nClosing the contact list...\n");
break;
}
}
}

private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;
};

int main(){
//add code below this line

Contacts contacts;
contacts.Display();

//add code above this line

return 0;
}
Lab 2

Adding a Contact
The first thing we need to do is to change the default view when a Contacts
object is instantiated. The list view should be the first view shown to the
user. Change the value for view from "quit" to "list" in the constructor.
The rest of the constructor should not be changed.

Code from Lab 1

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "quit";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}

void DisplayInfo() {

}
void AddInfo() {

void ShowList() {

void Display() {
while (true) {
if (view==("list")) {
ShowList();
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout<< " "<<endl;
AddInfo();
}
else if (view==("quit")) {
cout << ("\nClosing the contact list...\n");
break;
}
}
}

private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;
};

//add class definitions above this line

int main(){

//add code below this line

Contacts contacts;
contacts.Display();
//add code above this line

return 0;

public:
Contacts() {
view = "list";
// rest of the constructor remains unchanged
}

Next we want to modify the ShowList function to show the list of people in
the contact list. There are two possible states for the list view: the list is
empty or there are contacts in the list. When the list is empty, the user will
be provided with the choice to add a contact or quit the program. Use a
conditional to represent these two states. For now, set view to "quit" in the
else branch.

The print statement is to add a blank line for legibility. We also need a cin
object to collect input from the user. If length is 0, then present the user
with a choice. Store their input in choice. The .tolower() function will
convert the user choice to a lowercase letter. This will make comparisons
easier. Remember, C++ is case sensitive; q and Q are not the same. By
forcing all input to lowercase, we only need to test for the lowercase letter.
The ShowList function ends by calling another function to handle the user’s
choice.

void ShowList() {
cout << endl;
char sc;
if (length == 0) {
cout << ("(A)dd a new contact \n(Q)uit \n> ");
cin >> sc;
choice = putchar(tolower(sc));
}
else {
view = "quit";
}
HandleChoice();
}

Handling User Choices


Every time the user makes a choice, we want to evaluate that choice and
perform the appropriate action. In this case, the user can choose between
adding a contact or quitting the program. Notice that view only changes to
"add" if "a" is entered and we are in list view. We only want to add new
contacts from the list view.

void HandleChoice() {
if (choice==("q")) {
view = "quit";
}
else if (choice==("a") && view==("list")) {
view = "add";
}
}

Adding a Contact
When the user enters "a", we need to create a new contact. To do this, we
are going to modify the AddInfo function. Use cout and the getline function
to ask the user to enter the name, personal phone number, personal email,
work title, work phone number, and work email, and then temporarily
store that information. Each piece of information should go into the
corresponding vector attribute after. Notice that we include cin >> ws
within getline because by doing so, we are able to consume the whitespace
ws. Once the information has been added, increase the length attribute and
revert back to the list view.
void AddInfo() {
cout << endl;
string sc2;
cout << ("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);

cout << ("Enter their personal phone number: ");


getline(cin >> ws, sc2);
string personalPhone = sc2;
personalPhoneNumbers.push_back(personalPhone);

cout << ("Enter their personal email: ");


getline(cin >> ws, sc2);
string personalEmail = sc2;
personalEmails.push_back(personalEmail);

cout << ("Enter their work title: ");


getline(cin >> ws, sc2);
string title = sc2;
titles.push_back(title);

cout << ("Enter their work phone number: ");


getline(cin >> ws, sc2);
string workPhone = sc2;
workPhoneNumbers.push_back(workPhone);

cout << ("Enter their work email: ");


getline(cin >> ws, sc2);
string workEmail = sc2;
workEmails.push_back(workEmail);
length++;
view = "list";
}

Testing Your Code


Before moving on to the next part of the program, we want to check that
our code is adding a contact to the list. To do that, we need to create a getter
for the length attribute.
int GetLength() {
return length;
}

Now call print the result from the GetLength function.

//add code below this line

Contacts contacts;
contacts.Display();
cout<< contacts.GetLength()<< endl;

//add code above this line

Run the program and enter a when prompted, then add the following
contact:

Rachel Kim
555 123-4567
[email protected]
Senior Software Engineer
555 890-1234
[email protected]

If everything worked properly, your program should print 1 in the terminal


as there is one person in our contact list.

Code

Your code should look like this:

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "list";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}

void DisplayInfo() {

void AddInfo() {
cout << endl;
string sc2;
cout << ("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);

cout << ("Enter their personal phone number: ");


getline(cin >> ws, sc2);
string personalPhone = sc2;
personalPhoneNumbers.push_back(personalPhone);

cout << ("Enter their personal email: ");


getline(cin >> ws, sc2);
string personalEmail = sc2;
personalEmails.push_back(personalEmail);

cout << ("Enter their work title: ");


getline(cin >> ws, sc2);
string title = sc2;
titles.push_back(title);

cout << ("Enter their work phone number: ");


getline(cin >> ws, sc2);
string workPhone = sc2;
workPhoneNumbers.push_back(workPhone);

cout << ("Enter their work email: ");


getline(cin >> ws, sc2);
string workEmail = sc2;
workEmails.push_back(workEmail);
length++;
view = "list";
}

int GetLength() {
return length;
}

void HandleChoice() {
if (choice==("q")) {
view = "quit";
}
else if (choice==("a") && view==("list")) {
view = "add";
}
}

void ShowList() {
cout << endl;
char sc;
if (length == 0) {
cout << ("(A)dd a new contact \n(Q)uit \n> ");
cin >> sc;
choice = putchar(tolower(sc));
}
else {
view = "quit";
}
HandleChoice();
}

void Display() {
while (true) {
if (view==("list")) {
ShowList();
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout << endl;
AddInfo();
}
else if (view==("quit")) {
cout << ("\nClosing the contact list...\n");
break;
}
}
}

private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;
};

//add class definitions above this line

int main(){

//add code below this line

Contacts contacts;
contacts.Display();
cout << contacts.GetLength() << endl;

//add code above this line

return 0;

}
Lab 3

Displaying the List View


Now that we can add a contact to the list, we will want to show all of the
contacts in the list.

Code from Lab 2

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "list";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}

void DisplayInfo() {

void AddInfo() {
cout << endl;
string sc2;
cout << ("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);

cout << ("Enter their personal phone number: ");


getline(cin >> ws, sc2);
string personalPhone = sc2;
personalPhoneNumbers.push_back(personalPhone);

cout << ("Enter their personal email: ");


getline(cin >> ws, sc2);
string personalEmail = sc2;
personalEmails.push_back(personalEmail);

cout << ("Enter their work title: ");


getline(cin >> ws, sc2);
string title = sc2;
titles.push_back(title);

cout << ("Enter their work phone number: ");


getline(cin >> ws, sc2);
string workPhone = sc2;
workPhoneNumbers.push_back(workPhone);

cout << ("Enter their work email: ");


getline(cin >> ws, sc2);
string workEmail = sc2;
workEmails.push_back(workEmail);
length++;
view = "list";
}

int GetLength() {
return length;
}

void HandleChoice() {
if (choice==("q")) {
view = "quit";
}
else if (choice==("a") && view==("list")) {
view = "add";
}
}
void ShowList() {
cout << endl;
char sc;
if (length == 0) {
cout << ("(A)dd a new contact \n(Q)uit \n> ");
cin >> sc;
choice = putchar(tolower(sc));
}
else {
view = "quit";
}
HandleChoice();
}

void Display() {
while (true) {
if (view==("list")) {
ShowList();
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout << endl;
AddInfo();
}
else if (view==("quit")) {
cout << ("\nClosing the contact list...\n");
break;
}
}
}

private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;
};

//add class definitions above this line


int main(){

//add code below this line

Contacts contacts;
contacts.Display();
cout << contacts.GetLength() << endl;

//add code above this line

return 0;

But before doing that, we need to remove the print statement at the end of
the script. The final two lines of code should look like this:

//add code below this line

Contacts contacts;
contacts.Display();

//add code above this line

We are going to iterate through the list of contacts and print the name. To
help users select a contact, a number will appear before each name. This
way, the user types the number, and the contact’s information appears.
Previously, the cin object stored the user input as a char, but since we want
the user to be able to input numbers now, we have to change the input sc
to a string instead. Then we create a loop in which sc gets iterated and each
character will be converted into lowercase and added to the string choice.
In the else branch function, create a for loop to go from 0 to length. We
want a number followed by the name. The numbers should start at 1, so
print the loop index plus 1 followed by the element from the names vector.
After displaying the list of names, ask the user to make a selection. Entering
a number will show all of the information about a contact. After
HandleChoice is called, be sure to set choice back to an empty string;
otherwise, the user’s input will continue to be stored in choice and
negatively affect the acceptable input requirement.
void ShowList() {
cout << endl;
string sc;
if (length == 0) {
cout << ("(A)dd a new contact \n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
else {
for (int i = 0; i < length; i++) {
cout << (i + 1 ) << ") " << names.at(i) << endl;
}
cout << ("\n(#) Select a name \n(A)dd a new
contact\n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
HandleChoice();
choice = "";
}

Handling Numeric Input


Add an else if branch to the HandleChoice function that asks if the user
input is numeric (remember, the cin object now stores user input as a
string) and if the user is in the list view. If yes, then convert the user input
to an integer, subtract 1, and store it in the variable num. Remember, we
added one to the loop index in the ShowList function. If the user made a
mistake in entering the number, the script will crash if you try to access an
index that is outside of the vector. So we need to verify that the number is
between 0 and length. Finally, set index to num and set view to "info".
void HandleChoice() {
if (choice==("q")) {
view = "quit";
}
else if (choice==("a") && view==("list")) {
view = "add";
}
else if (IsNumeric(choice) && view==("list")) {
int num = (stoi(choice) - 1);
if (num >= 0 && num < length) {
index = num;
view = "info";
}
}
}

We need to create the boolean helper function IsNumeric which takes the
user input and determines if they entered a number. First see if the user
input (a string) is empty. Return false if either condition is true. Then try to
convert the string to an integer. If this works, return true. If C++ throws an
exception because the string cannot be converted to an integer, then return
false. Since IsNumeric is a helper function, you should encapsulate it as
private.

bool IsNumeric(string s) {
int value;

if (s == "") {
return false;
}

try {
value = stoi(s);
return true;
}
catch (runtime_error& e) {
return false;
}
}

Testing Your Code


Before moving on to the next part of the program, we want to check that
our code is displaying all of the contacts in the list. To do that, enter two
different contacts. The first one is:
John Calvin
555 111-2222
[email protected]
Philosopher
555 333-4444
[email protected]

You should see a list that looks like this:

.guides/img/Polymorphism/lab3_pic1

Now add a second contact to the list:

Thomas Hobbes
555 666-7777
[email protected]
Philosopher
555 888-9999
[email protected]

Your program should now show the following output:

.guides/img/Polymorphism/lab3_pic2

Code

Your code should look like this:

#include <iostream>
#include <vector>
using namespace std;
//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "list";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}

void DisplayInfo() {

void AddInfo() {
cout << endl;
string sc2;
cout << ("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);

cout << ("Enter their personal phone number: ");


getline(cin >> ws, sc2);
string personalPhone = sc2;
personalPhoneNumbers.push_back(personalPhone);

cout << ("Enter their personal email: ");


getline(cin >> ws, sc2);
string personalEmail = sc2;
personalEmails.push_back(personalEmail);

cout << ("Enter their work title: ");


getline(cin >> ws, sc2);
string title = sc2;
titles.push_back(title);

cout << ("Enter their work phone number: ");


getline(cin >> ws, sc2);
string workPhone = sc2;
workPhoneNumbers.push_back(workPhone);

cout << ("Enter their work email: ");


getline(cin >> ws, sc2);
string workEmail = sc2;
workEmails.push_back(workEmail);
length++;
view = "list";
}

int GetLength() {
return length;
}

void HandleChoice() {
if (choice==("q")) {
view = "quit";
}
else if (choice==("a") && view==("list")) {
view = "add";
}
else if (IsNumeric(choice) && view==("list")) {
int num = (stoi(choice) - 1);
if (num >= 0 && num < length) {
index = num;
view = "info";
}
}
}

void ShowList() {
cout << endl;
string sc;
if (length == 0) {
cout << ("(A)dd a new contact \n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
else {
for (int i = 0; i < length; i++) {
cout << (i + 1 ) << ") " << names.at(i) << endl;
}
cout << ("\n(#) Select a name \n(A)dd a new
contact\n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
HandleChoice();
choice = "";
}

void Display() {
while (true) {
if (view=="list") {
ShowList();
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout << endl;
AddInfo();
}
else if (view==("quit")) {
cout << ("\nClosing the contact list...\n");
break;
}
}
}

private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;

bool IsNumeric(string s) {
int value;

if (s == "") {
return false;
}

try {
value = stoi(s);
return true;
}
catch (runtime_error& e) {
return false;
}
}
};

//add class definitions above this line

int main(){

//add code below this line

Contacts contacts;
contacts.Display();

//add code above this line

return 0;

}
Lab 4

Displaying Contact Info


The next step is to display the contact information for a selected contact.

Code from Lab 3

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "list";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}

void DisplayInfo() {

void AddInfo() {
cout<< endl;
string sc2;
cout<<("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);

cout<<("Enter their personal phone number: ");


getline(cin >> ws, sc2);
string personalPhone = sc2;
personalPhoneNumbers.push_back(personalPhone);

cout<<("Enter their personal email: ");


getline(cin >> ws, sc2);
string personalEmail = sc2;
personalEmails.push_back(personalEmail);

cout<<("Enter their work title: ");


getline(cin >> ws, sc2);
string title = sc2;
titles.push_back(title);

cout<<("Enter their work phone number: ");


getline(cin >> ws, sc2);
string workPhone = sc2;
workPhoneNumbers.push_back(workPhone);

cout<<("Enter their work email: ");


getline(cin >> ws, sc2);
string workEmail = sc2;
workEmails.push_back(workEmail);
length++;
view = "list";
}

int GetLength() {
return length;
}

void HandleChoice() {
if (choice==("q")) {
view = "quit";
}
else if (choice==("a") && view==("list")) {
view = "add";
}
else if (IsNumeric(choice) && view==("list")) {
int num = (stoi(choice) - 1);
if (num >= 0 && num < length) {
index = num;
view = "info";
}
}
}

void ShowList() {
cout<< endl;
string sc;
if (length == 0) {
cout<< ("(A)dd a new contact \n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
else {
for (int i = 0; i < length; i++) {
cout<< (i + 1 ) << ") " << names.at(i)<<endl;
}
cout<< ("\n(#) Select a name \n(A)dd a new
contact\n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
HandleChoice();
choice = "";
}

void Display() {
while (true) {
if (view==("list")) {
ShowList();
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout<< endl;
AddInfo();
}
else if (view==("quit")) {
cout<< ("\nClosing the contact list...\n");
break;
}
}
}
private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;

bool IsNumeric(string s) {
int value;

if (s == "") {
return false;
}

try {
value = stoi(s);
return true;
}
catch (runtime_error& e) {
return false;
}
}
};

//add class definitions above this line

int main(){

//add code below this line

Contacts contacts;
contacts.Display();

//add code above this line

return 0;

}
On the previous page, we already modified HandleChoice to deal with
numeric input. So let’s update the DisplayInfo function to display the
information. Print the elements from each vector using the attribute index.
After the information is displayed, change view back to "list" and then call
ShowList.

void DisplayInfo() {
cout<< endl;
cout<<names.at(index)<<endl;
cout<<"Personal email address: " << personalEmails.at(index)
<<endl;
cout<<"Personal phone number: " <<
personalPhoneNumbers.at(index)<<endl;
cout<<"Work title: " << titles.at(index)<<endl;
cout<<"Work email address: " << workEmails.at(index)<<endl;
cout<<"Work phone number: " << workPhoneNumbers.at(index)
<<endl;
view = "list";
ShowList();
}

Testing Your Code


This program should be complete now. To test it, add at least two contacts.
Select one of the contacts by entering the correlated number. Keep entering
a number to display the relevant contact information, a to add additional
contacts, or q to quit the program.

Code

Your code should look like this:

#include <iostream>
#include <vector>
using namespace std;

//add class definitions below this line

class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};

class Contacts : public Information {


public:
Contacts() {
view = "list";
names = {};
titles = {};
workPhoneNumbers = {};
workEmails = {};
personalPhoneNumbers = {};
personalEmails = {};
choice = "";
index = 0;
length = 0;
}

void DisplayInfo() {
cout<< endl;
cout<<names.at(index)<<endl;
cout<<"Personal email address: " <<
personalEmails.at(index)<<endl;
cout<<"Personal phone number: " <<
personalPhoneNumbers.at(index)<<endl;
cout<<"Work title: " << titles.at(index)<<endl;
cout<<"Work email address: " << workEmails.at(index)
<<endl;
cout<<"Work phone number: " << workPhoneNumbers.at(index)
<<endl;
view = "list";
ShowList();
}

void AddInfo() {
cout<< endl;
string sc2;
cout<<("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);

cout<<("Enter their personal phone number: ");


getline(cin >> ws, sc2);
string personalPhone = sc2;
personalPhoneNumbers.push_back(personalPhone);

cout<<("Enter their personal email: ");


getline(cin >> ws, sc2);
string personalEmail = sc2;
personalEmails.push_back(personalEmail);

cout<<("Enter their work title: ");


getline(cin >> ws, sc2);
string title = sc2;
titles.push_back(title);
cout<<("Enter their work phone number: ");
getline(cin >> ws, sc2);
string workPhone = sc2;
workPhoneNumbers.push_back(workPhone);

cout<<("Enter their work email: ");


getline(cin >> ws, sc2);
string workEmail = sc2;
workEmails.push_back(workEmail);
length++;
view = "list";
}

int GetLength() {
return length;
}

void HandleChoice() {
if (choice==("q")) {
view = "quit";
}
else if (choice==("a") && view==("list")) {
view = "add";
}
else if (IsNumeric(choice) && view==("list")) {
int num = (stoi(choice) - 1);
if (num >= 0 && num < length) {
index = num;
view = "info";
}
}
}

void ShowList() {
cout<< endl;
string sc;
if (length == 0) {
cout<< ("(A)dd a new contact \n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
else {
for (int i = 0; i < length; i++) {
cout<< (i + 1 ) << ") " << names.at(i)<<endl;
}

cout<< ("\n(#) Select a name \n(A)dd a new


cout<< ("\n(#) Select a name \n(A)dd a new
contact\n(Q)uit \n> ");
cin >> sc;
for (char c : sc) {
choice += (tolower(c));
}
}
HandleChoice();
choice = "";
}

void Display() {
while (true) {
if (view==("list")) {
ShowList();
}
else if (view==("info")) {
DisplayInfo();
}
else if (view==("add")) {
cout<< endl;
AddInfo();
}
else if (view==("quit")) {
cout<< ("\nClosing the contact list...\n");
break;
}
}
}

private:
string view;
vector<string> names;
vector<string> titles;
vector<string> workPhoneNumbers;
vector<string> workEmails;
vector<string> personalPhoneNumbers;
vector<string> personalEmails;
string choice;
int index;
int length;

bool IsNumeric(string s) {
int value;

if (s == "") {
return false;
}

try {
value = stoi(s);
return true;
}
catch (runtime_error& e) {
return false;
}
}
};

//add class definitions above this line

int main(){

//add code below this line

Contacts contacts;
contacts.Display();

//add code above this line

return 0;

}
Lab Challenge

Problem

In the IDE to the left, the class Chef is already defined, as is the Display
function. However, it does not have a constructor. Create three
constructors that take one, two, and three parameters respectively. Note
that the attributes name and cuisine are set to "null" while michelinStars is
set to 0 by default.

Given Code

#include <iostream>
using namespace std;

//add class definitions below this line

class Chef {
public:

//add constructors below this line

//add constructors above this line

string GetName() {
return name;
}

string GetCuisine() {
return cuisine;
}

int GetStars() {
return michelinStars;
}

void Display() {
cout << GetName() << " is known for " << GetCuisine() << "
cuisine and has " << GetStars() << " Michelin stars." <<
endl;
}
private:
string name = "null";
string cuisine = "null";
int michelinStars = 0;
};

//add class definitions above this line

int main() {

//DO NOT EDIT code below this line

Chef c1("Marco Pierre White");


Chef c2("Rene Redzepi", "Nordic");
Chef c3("Thomas Keller", "French", 3);

c1.Display();
c2.Display();
c3.Display();

//DO NOT EDIT code above this line

return 0;

Expected Output

Three Chef objects are instantiated, each one using a different constructor.
Calling the Display function for each object should return the following
text:

Function Call Return Value


Marco Pierre White is known for
c1.Display() null cuisine and has 0 Michelin
stars.
Rene Redzepi is known for
c2.Display() Nordic cuisine and has 0
Michelin stars.
Thomas Keller is known for
c3.Display() French cuisine and has 3
Michelin stars.
Learning Objectives: Advanced
Topics

Include and create an object defined in a separate file

Understand what the scope resolution operator does

Manipulate class variables not attached to a class object

Create structs and enums

Compare objects
Using #include

Objects Defined in Other Files


Now that you’re familiar with creating, manipulating, and inheriting
objects, we’ll discuss how these concepts all come together when programs
are created. You may have noticed that a lot of the classes that you’ve
previously worked with is fairly lengthy. In fact, it’s not typical to include
class definitions within the same file as the main program. Usually, classes
are defined in other files but they can be accessed by the main program if
you set up the correct encapsulation.

“#include” in the Header


Ever noticed how #include <iostream> and using namespace std; are
usually present in the header of the file? The #include directs the system to
look for the file or library iostream. Then using namespace std; enables the
system to access functions from the class std without having to use the
scope resolution operator ::.

.guides/img/advanced/Include

Enter the following into main and Try It.

cout << "Hello world" << endl;


Next, comment the header line using namespace std; and run the program
again.

#include <iostream>
//using namespace std;

Without using namespace std;, the system has no clue which class to look
into to use cout. Now revise the code in main to look like this:

std::cout << "Hello world" << std::endl;

The scope resolution operator :: does the same job as using namespace
std;. Note that you will need to use std:: in front of every function you
decide to call.

Calling Functions From a Separate File


In the upper left of the text editor window, you will notice a tab that says
class.h. Click on this tab to see the content of the file.

.guides/img/advanced/HeaderFile

This is a header file which you can use to store your class definitions. There
is some syntax (at the beginning and the end) that you have to include in
order to specify that class.h is a header file, but ultimately you can reduce
the number of code in your main program by creating header files. All
header files should have #ifndef and #define (followed by their file name
and then an underscore _ and H) in their header and #endif towards the
end.
Now, go back into include.cpp, copy the entire code below and TRY IT.

//#include <iostream>
//using namespace std;
#include "class.h"

int main() {

//add code below this line

Greeting g("Hello world");


cout << g.GetGreeting() << endl;
g.SetGreeting("Hi world");
cout << g.GetGreeting() << endl;

//add code above this line

return 0;

Notice how we used #include "class.h" in the header of our file. This
enables a connection between the main file and the header file class.h
where the class definitions are found. Also note that because #include
<iostream> and using namespace std; are already included in class.h, you
can comment out or remove them in the main program.
Static Variables & Functions

Manipulating Non-Object Variables


Throughout this course, we’ve been creating class objects through the use
of a constructor, which is required in order for an object to access certain
class functions. However, if we want to manipulate a particular class
attribute without having to instantiate that particular object, you can use a
combination of the static keyword plus the scope resolution operator :: to
manipulate attributes. Copy the code below and TRY IT.
#include <iostream>
using namespace std;

//add class definitions below this line

class Player {
public:
Player() {
health = 100;
score = 0;
level = 1;
}
void PrintLevel() {
cout << level << endl;
}
static int ChangeLevel(int change) { //define static
function
level = change;
return level;
}

private:
int health;
int score;
static int level; //declare static variable
};

//add class definitions above this line

int Player::level = 0; //initalize static variable globally

int main() {

//add code below this line

Player mario;
mario.PrintLevel(); //calling class function, object required
cout << Player::ChangeLevel(5) << endl; //calling static
function, object not needed

//add code above this line

return 0;

Notice how when calling the ChangeLevel function, we needed the class
name Player followed by the scope resolution operator :: followed by the
function name ChangeLevel and any parameter arguments. Calling a static
function enabled us to change the attribute level to 5 without calling the
function on the object itself.

When defining and calling static functions, keep the following in mind:
* Within a class, static functions can only access other static members; for
example, if level was not a static variable in the example above,
ChangeLevel will not be able to access it.
* A static variable should be defined or initialized globally outside of any
class or function. In other words, a static variable should not be initialized
within a class or within the main function.
* Use the scope resolution operator :: as defined above to access static
functions that modify static variables.

Static Variables
It’s important to note that static variables are variables that are created
only once. They cannot be created again for the duration of the program.
The following code will showcase how the static variable level works
throughout the program.
#include <iostream>
using namespace std;

//add class definitions below this line

class Player {
public:
Player() {
health = 100;
score = 0;
}
void PrintLevel() {
cout << level << endl;
}
static int ChangeLevel(int change) {
level = change;
return level;
}

private:
int health;
int score;
static int level;
};

//add class definitions above this line

int Player::level = 5; //initialize static variable level to 5

int main() {

//add code below this line

Player mario;
mario.PrintLevel();
cout << Player::ChangeLevel(6) << endl;
Player luigi;
luigi.PrintLevel();

//add code above this line

return 0;

}
Again, note that static variables are initialized outside of a class globally.
This is to prevent the variable from being duplicated. By definition, static
variables are only created once. This is why when the Player object luigi is
created, its level attribute is the same as mario’s even though its level was
never changed. Essentially, both objects share the same static variable
level. Changes made to level will be reflected in all objects that have that
attribute.
Structs & Enums

What are Structs?


Structs are like classes, except everything inside a struct is public.
Therefore, anything external to the struct can alter its members. For
example:

//add class definitions below this line

struct Person {
string name;
int age;
double salary;
};

//add class definitions above this line

int main() {

//add code below this line

Person p;
p.age = 50;
cout << p.age << endl;

//add code above this line

return 0;

In the example above, after creating the struct called Person, we are able to
access the age attribute by simply using dot notation and specifying the
attribute. If security is not an issue, structs are useful at putting together a
collection of attributes that are highly modifiable and accessible.

Setting Values with Enums


Enums are similar to switch-case statements where particular values are
assigned to particular cases. See example below:
//add class definitions below this line

enum grades {A = 90, B = 80, C = 70, D = 60};

//add class definitions above this line

int main() {

//add code below this line

grades grade;

grade = A;
cout << "Grade = " << grade << endl;

//add code above this line

return 0;

Cases (variables) of the alphabet from A through D have been assigned to


variable integers from 90 backwards to 60 in increments of 10. When you
create a grades enum, you can assign it to any of the cases specified in the
enum definition. This will signal to the system to assign the grades enum to
appropriate integer equivalent.

NOTE: Enum values must be integers. For example, you can’t create an
enum with string values.

challenge

Try this variation:


Change enum grades {A = 90, B = 80, C = 70, D = 60}; in the
code above to enum grades {A, B, C, D};.
Change grade = A; to grade = B;.
Change enum grades {A, B, C, D}; to enum grades {A = 90, B, C,
D};.
Change enum grades {A = 90, B, C, D}; to enum grades {A, B, C
= 5, D};.
Change grade = B; to grade = D;.
NOTE: If the enum variables are not assigned values, the first variable will
be 0 by default. The second variable will be 1 and so on. Additionally, the
incrementation of 1 happens following the first value of the initialized
enum variable. For example, enum fruit {apple = 5, banana, orange};
causes apple to have a value of 5 and each variable after will have a value
incremented by 1. This means banana will have a value of 6 and orange will
have a value of 7. On the other hand, enum fruit {apple, banana = 5,
orange}; causes apple to be 0, banana to be 5, and orange to be 6.
Object Equality

Comparing Object Types


You can compare object types by implementing the typeid function. For
example, the code below showcases the comparison between two Player
objects called mario and luigi using typeid.

//add class definitions below this line

class Player {
public:
Player() {
health = 100;
score = 0;
level = 1;
}

private:
int health;
int score;
int level;
};

//add class definitions above this line

int main() {

//add code below this line

Player mario;
Player luigi;
cout << boolalpha;
cout << (typeid(mario) == typeid(luigi)) << endl;

//add code above this line

return 0;

}
Since both mario and luigi are of the class Player, their typeid will be the
same. This is why cout << (typeid(mario) == typeid(luigi)) << endl;
returns true. Unfortunately, typeid does not check to ensure that both
objects contain the same exact attribute values. However, you can create a
user-defined class to check for that.

Comparing Same-Class Objects


Let’s create a static member function called ComparePlayers. This function
takes in two Player objects as parameters, then checks to see if each of
their attributes is equal to the other. If their attributes are equal, true is
returned. Else, false is returned. Another member function called
NextLevel is also created.

//add class definitions below this line

class Player {
public:
Player() {
health = 100;
score = 0;
level = 1;
}

static bool ComparePlayers(Player p1, Player p2) {


if ((p1.health == p2.health) &&
(p1.score == p2.score) &&
(p1.level == p2.level)) {
return true;
}
else {
return false;
}
}

void NextLevel() {
level++;
}

private:
int health;
int score;
int level;
};

//add class definitions above this line


int main() {

//add code below this line

Player mario;
Player luigi;
cout << boolalpha;
cout << Player::ComparePlayers(mario, luigi) << endl;

//add code above this line

return 0;

challenge

Try this variation:


Replace the code in main with:

//add code below this line

Player mario;
Player luigi;
cout << boolalpha;
mario.NextLevel();
cout << Player::ComparePlayers(mario, luigi) << endl;

//add code above this line

Notice how when mario’s level changed, the ComparePlayers function


returns false when mario and luigi are compared.
Lab 1

Lab 1
In this module, we’ve learned how to create separate header files so that
we can call them without having to place them into the main file. This will
dramatically reduce the length of code needed in the main file. Make sure
your main file (lab1.cpp) and your header file (class.h) contain the code
below.

main

#include "class.h"

int main() {

//add code below this line

Greeting g("Hello world");


cout << g.GetGreeting() << endl;
g.SetGreeting("Hi world");
cout << g.GetGreeting() << endl;

//add code above this line

return 0;

header
#ifndef CLASS_H
#define CLASS_H
#include <iostream>
using namespace std;

//add class definitions below this line

class Greeting {
public:
Greeting(string g) {
greeting = g;
}

string GetGreeting() {
return greeting;
}

void SetGreeting(string new_greeting) {


greeting = new_greeting;
}

void PrintGreeting(){
cout << GetGreeting() << endl;
}

private:
string greeting;
};

//add class definitions above this line

#endif

Now, try to add to the existing class.h by including a class called Farewell.
This class should include all of the equivalent functions of Greeting.

For example, if:

Farewell f("Goodbye world");


cout << f.GetFarewell() << endl;
f.SetFarewell("Bye world");
cout << f.GetFarewell() << endl;

Then the result should be:


Goodbye world
Bye world
Lab 2

Lab 2
You are provided the following header and main files:

point.h

#ifndef SLOPE_H
#define SLOPE_H

//add definitions below this line

//add definitions above this line

#endif

slope.h

#ifndef SLOPE_H
#define SLOPE_H

//add definitions below this line

//add definitions above this line

#endif

lab2.cpp
#include <iostream>
using namespace std;
#include "point.h"
#include "slope.h"

int main() {

//add code below this line

//add code above this line

return 0;

In this lab, you’ll be working with these three files. The idea is to create a
struct called point within point.h, then create a static function called
CalculateSlope within slope.h, and finally run a few commands within
lab2.cpp to print some results.

point.h
In this header file, we will create a struct called point which contains just
two attributes, int x and int y. Remember, structs are public by default
which means they are easily accessible.

//add definitions below this line

struct point {
int x;
int y;
};

//add definitions above this line

slope.h
In this header file, we will create a class called Slope. This class only has
one static member function called CalculateSlope. CalculateSlope takes in
two point structures and returns the calculated slope between them.
//add definitions below this line

class Slope {
public:
static double CalculateSlope(point a, point b) {
return ( (double) (b.y - a.y) / (double) (b.x - a.x) );
}
};

//add definitions above this line

lab2.cpp
Now it’s time to test our header files within main. We are going to create
two point structures, assign values to their attributes, then call
CalculateSlope on the two points. Note that we do not need to create a
Slope object before calling CalculateSlope since it is a static function.
Simply use the scope resolution operator :: to access the function as shown
in the code below.

//add code below this line

point a;
point b;
a.x = 0;
a.y = 0;
b.x = 2;
b.y = 2;
cout << Slope::CalculateSlope(a, b) << endl;

//add code above this line

challenge

Try these variations:


Replace the code in main with:
//add code below this line

point a;
point b;
a.x = 1;
a.y = 2;
b.x = 10;
b.y = 20;
cout << Slope::CalculateSlope(a, b) << endl;

//add code above this line

Change the entire lab2.cpp to look like this:


#include <iostream>
using namespace std;

struct point {
int x;
int y;
};

class Slope {
public:
static double CalculateSlope(point a, point b) {
return ( (double) (b.y - a.y) / (double) (b.x - a.x)
);
}
};

int main() {

//add code below this line

point a;
point b;
a.x = 1;
a.y = 2;
b.x = 10;
b.y = 20;
cout << Slope::CalculateSlope(a, b) << endl;

//add code above this line

return 0;

Note that including the header files produces the same result as including
the struct point and class Slope within main. However, the header files
enable the main program to be less cluttered with definitions.
Lab Challenge

Problem

Create a BankAccount struct in the IDE to the left which has two double
attributes checking and savings. Create a function called ToString within
the struct that prints a representation of a BankAccount struct which
includes these attributes.

You MUST use struct within your code in order to receive credit for this
challenge.

Given Code

#include <iostream>
#include <iomanip>
using namespace std;

//add definitions below this line

//add definitions above this line

int main() {

//DO NOT EDIT code below this line

BankAccount account1;
account1.checking = 2432;
account1.savings = 89.52;
BankAccount account2;
account2.checking = 1998;
account2.savings = 239.43;
account1.ToString();
account2.ToString();

//DO NOT EDIT code above this line

return 0;

}
Setting decimal places

You can use the code cout << setprecision(2) << fixed followed by a
specified value to set that value to two decimal places.

Testing Your Code


The code in main is used to test your definitions. DO NOT EDIT this code!

//DO NOT EDIT code below this line

BankAccount account1;
account1.checking = 2432;
account1.savings = 89.52;
BankAccount account2;
account2.checking = 1998;
account2.savings = 239.43;
account1.ToString();
account2.ToString();

//DO NOT EDIT code above this line

Expected Result

BankAccount[checking=2432.00, savings=89.52]
BankAccount[checking=1998.00, savings=239.43]

You might also like