C++ Notes
C++ Notes
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.
.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.
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
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(/).
*/
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
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.
1. a data type
2. a name
3. a value
We will discuss each of these parts over the rest of this reading assignment.
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.
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
challenge
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.
challenge
important
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.
challenge
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
.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.
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
int one = 1;
int two = 2;
int three = 3;
int four = 4;
two = one;
three = two;
four = three;
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
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.
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
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
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().
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
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
String Concatenation
String concatenation is the act of combining two strings together. This is
done with the + operator.
challenge
Subtraction
Copy the code below and TRY IT.
int a = 10;
int b = 3;
int c = a - b;
cout << c << endl;
challenge
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.
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.
Division
Division in C++ is done with the / operator.
double a = 25.0;
double b = 4.0;
printf("%f \n", a / b);
challenge
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
Multiplication
C++ uses the * operator for multiplication.
int a = 5;
int b = 10;
cout << a * b << endl;
challenge
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
int a = 2;
int b = 3;
int c = 4;
double result = 3 * a - 2 / (b + 5) + c;
printf("%f \n", result);
Explanation
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.
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.
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;
Output
Function Input Type Example
Type
stoi() string int stoi(“10”)
challenge
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
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
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
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
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.
int a = 5;
int b = 7;
cout << boolalpha << (a <= b) << endl;
challenge
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
Hint(s)
9 is both greater than the value of false, which is 0, and the value of true,
which is 1.
int a = 9;
int b = 17;
cout << boolalpha << (a >= b) << endl;
challenge
Hint(s)
true is greater than false.
And
bool a = true;
bool b = true;
bool c = false;
cout << boolalpha << (a && b) << endl;
challenge
bool a = true;
bool b = true;
bool c = false;
cout << boolalpha << (a && b && c) << endl;
challenge
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;
challenge
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
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.
challenge
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.
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
Use the text editor on the left to enter the following code:
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
Use the text editor on the left to enter the following code:
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
.guides/img/PEMDAS
Use the text editor on the left to enter the following code:
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
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.
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.
!= <= >= ||
!
Learning Objectives: If Else
Statement
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
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.
if (10 % 2 == 0)
cout << "10 is even" << endl;
else
cout << "10 is odd" << endl;
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.
if (my_bool) {
cout << "The value of my_bool is true" << endl; }
else {
cout << "The value of my_bool is false" << endl; }
challenge
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; }
.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.
Code Visualizer
Learning Objectives: Switch Case
Statement
.guides/img/SwitchCase
switch (dayOfWeek) {
Code Visualizer
challenge
Code Visualizer
Switch Case vs. If Else
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
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
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).
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";
}
challenge
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++;
}
int x = 5;
if (x < 10) {
cout << "Less than 10" << endl;
}
Code Visualizer
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;
}
Code Visualizer
if (age < 20) { if ((age < 20) && (age > 10)) {
if (age > 10) { cout << "Teenager";
cout << "Teenager"; }
}
Code Visualizer
Lab: If Else Statement
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 }.
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
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
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.
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.
Code Visualizer
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
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.
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:
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.
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
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:
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
tina.pencolor({"blue"});
tina.width(2);
tina.shape("arrow");
tina.speed(TS_SLOWEST);
tina.pencolor({"red"});
tina.width(2);
tina.shape("square");
tina.speed(TS_FASTEST);
tina.pencolor({"green"});
tina.width(2);
tina.shape("triangle");
tina.speed(TS_NORMAL);
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.
Code Visualizer
challenge
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:
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.
int player_lives = 3;
Instead of a for loop, recreate the images below using a while loop.
Challenge 1
.guides/img/TurtleChallenge1
Hint
The pattern 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
Take a look at the following program (also shown in the text editor on the
left).
#include <iostream>
using namespace std;
int main() {
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
Code Visualizer
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
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.
Code Visualizer
challenge
Code Visualizer
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.
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).
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++;
}
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
int counter = 0;
while (counter < 10) {
cout << counter << endl;
counter = counter + 1;
}
cout << "while loop ended" << endl;
Code Visualizer
Program Summary
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
.guides/img/NestedLoopExample
.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.
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
XOXOXOXOX
OXO
OXO
Try creating that particular pattern first, then iterate that pattern by
modifying the existing loop(s).
Learning Objectives: Array Basics
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.
Code Visualizer
challenge
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.
Code Visualizer
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.
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];
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.
challenge
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.
challenge
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.
challenge
IMPORTANT
Here are some key points to keep in mind when working with arrays:
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.
Code Visualizer
challenge
Code Visualizer
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
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.
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.
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 ().
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.
challenge
challenge
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.
cout << Camry << endl; //print whether Camry exists or not
challenge
Sample Solution
string cars[] = {"Corolla", "Camry", "Prius", "RAV4",
"Highlander"};
string Prius = "A Prius is not available.";
cout << "The lowest grade is " << min << endl; //print lowest
element
challenge
Sample Solution
int grades[] = {72, 84, 63, 55, 98};
int max = grades[0];
cout << "The highest grade is " << max << endl;
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);
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);
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);
vector<int> numbers(3);
int digits[3];
challenge
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
cout << numbers.at(0) << endl; //50 becomes first and only
element
challenge
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.
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;
challenge
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.
challenge
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
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;
challenge
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
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
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.
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)
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");
challenge
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");
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.
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");
cout << Camry << endl; //print whether Camry exists or not
challenge
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");
vector<int> grades(0);
grades.push_back(72);
grades.push_back(84);
grades.push_back(63);
grades.push_back(55);
grades.push_back(98);
cout << "The lowest grade is " << min << endl; //print lowest
element
challenge
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);
cout << "The highest grade is " << max << endl;
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
.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.
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];
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.
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 ,.
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.
names[1][2] = "Harry";
cout << names[1][2] << endl;
challenge
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.
Code Visualizer
challenge
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} };
Code Visualizer
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
classes[4] = "French";
Program Summary
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";
Program Summary
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];
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
Declare 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:
int* p;
challenge
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 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;
Code Visualizer
challenge
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.
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 *.
Code Visualizer
challenge
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).
int a = 5;
int* p = &a;
int** p2 = &p;
Code Visualizer
challenge
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.
Code Visualizer
Remember: The row index [3] is optional but the column index [6] is
mandatory.
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" };
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
bool b = true;
bool* p = &b;
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
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.
#include <iostream>
using namespace std;
int main() {
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:
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.
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:
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.
challenge
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
.guides/img/StringAtIndex
string my_string = "Hello!";
char character = my_string.at(1);
challenge
Mutability
You now know how to reference each character of a string. What do you
think the code below will do?
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.
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).
.guides/img/MutabilityAssignment
Find
string my_string = "The brown dog jumps over the lazy fox.";
challenge
string my_string = "The brown dog jumps over the lazy fox.";
.guides/img/StringSubstr
string my_string = "The brown dog jumps over the lazy fox.";
string my_slice = my_string.substr(4, 9);
challenge
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.
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
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.
challenge
.guides/img/FindFirstOf
string string1 = "The brown dog jumps over the lazy fox.";
string string2 = "brown";
challenge
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");
challenge
challenge
my_string.replace(1, 2, "3")
challenge
string a = "High";
string b = " Five";
challenge
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
.guides/img/StringToUpper
challenge
challenge
challenge
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!
While Loop
String iteration is most often done with a for loop. However, a while can be
used as well.
challenge
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 !=
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.
challenge
Comparing with !=
You can also test for string inequality with the != operator.
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.
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
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
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";
The next thing to do is iterate over the string and to check each character of
the string. A enhanced for loop works best.
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;
}
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;
Code
int lower_count = 0;
int upper_count = 0;
string my_string = "Roses are Red, Violets are Blue";
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.
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);
All that’s left to do is print. Remember not to include endl or the system
will print a newline after each character.
Code
string my_string = "The brown dog jumps over the lazy fox";
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 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.
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
if (islower(ch))
If this is true, then append the uppercase version of the character to the
variable modified_string.
modified_string += toupper(ch);
else {
modified_string += tolower(ch);
}
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;
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;
cout << "The original string is: " + original_string << endl;
cout << "The modified string is: " + modified_string << endl;
Lab 4
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.
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.
Note that characters are wrapped in single quotes ' ', not double quotes in
C++.
Incrementing the Counter
count += 1;
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;
}
Code
string my_string = "The Brown Dog Jumps Over The Lazy Fox";
char ch;
int count = 0;
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
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;
return 0;
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
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.
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:
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
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
challenge
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.
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.
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
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
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
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).
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;
}
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;
}
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;
}
challenge
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;
}
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;
}
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;
}
challenge
Notice how you get the same result regardless of how your names are
organized in the text file.
Ignore Function
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
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.
try {
ofstream file;
file.open(path);
if (!file) {
throw runtime_error("File failed to open.");
}
}
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.";
}
Click on the link to open the file and see what was wrttien: Open
practice1.txt
challenge
Open 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();
}
challenge
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.
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();
}
Open practice2.txt
challenge
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.
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();
}
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
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
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.
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.
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
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.
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
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
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
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
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();
}
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.
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.
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.
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;
}
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;
}
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.
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.
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;
}
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.
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.
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:
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
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
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;
}
#include <iostream>
using namespace std;
void GreetTwice() {
cout << "Hello" << endl;
cout << "Hello" << endl;
}
int main() {
void GreetTwice() {
cout << "Hello" << endl;
cout << "Hello" << endl;
}
int main() {
GreetTwice();
}
challenge
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.
#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.
#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
/**
* 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
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
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
/**
* 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;
}
.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
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.
/**
* 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
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
/**
* 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
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
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
void MyFunction2() {
string my_var2 = "Hello";
cout << my_var2 << endl;
}
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
void MyFunction3() {
string my_var = "Hola";
cout << my_var << endl;
}
.guides/img/GlobalScope
void SayHello() {
cout << greeting << endl; //can access global variable
greeting
}
int main() {
SayHello();
return 0;
}
void SayHello() {
greeting = "Bonjour";
cout << greeting << endl;
}
int main() {
SayHello();
return 0;
}
challenge
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
void PrintScope() {
string my_var = "local scope";
cout << my_var << endl;
}
int main() {
PrintScope();
cout << my_var << endl;
}
void PrintScope() {
my_var = "local scope";
cout << my_var <<endl;
}
int main() {
PrintScope();
cout << my_var << endl;
}
challenge
int main() {
PrintScope(my_var);
cout << my_var << endl;
}
void PrintScope() {
kMyConstant = "I CAN'T CHANGE";
cout << kMyConstant << endl;
}
int main() {
PrintScope();
cout << kMyConstant << endl;
}
challenge
/**
* 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
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);
}
challenge
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);
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:
.guides/img/Radius
/**
* 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
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.
int main() {
GetSlope(3, 2, 5, 6);
return 0;
}
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
Global Variables
First, let’s add some global variables to our program.
double input1;
double input2;
double input3;
double input4;
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;
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;
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.
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;
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;
/**
* 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.
/**
* 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!
}
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;
Existing Code:
#include <iostream>
#include <vector>
using namespace std;
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.
create
create
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.
/**
* 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);
}
}
int main() {
Optional: Click the Code Visualizer link below to see how C++ handles this
recursive function behind-the-scenes.
Code Visualizer
.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
int Factorial(int n) {
if (n == 1) { //base case
return 1;
}
else { //recursive case
return n * Factorial(n - 1);
}
}
Try to modify the base case so that Factorial(0) does not result in
an error.
Solution
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
/**
* @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
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
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
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.
.guides/img/TurtleGraphicsFlow
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).
/**
* @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) {
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.
if (branch_length > 5) {
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.
if (branch_length > 5) {
t.forward(branch_length);
t.right(angle);
RecursiveTree(branch_length - 15, angle, t);
}
In main(), let’s call the RecursiveTree() function and pass in some initial
values.
int main(int argc, char** argv) {
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.
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);
}
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) {
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);
}
challenge
Code Sample
/**
* @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) {
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);
}
screen.exitonclick();
return 0;
}
Lab 2
Hilbert Curve
/**
* @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) {
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) {
if (depth > 0) {
if (rule == 1) {
//rule1 code
}
if (rule == 2) {
//rule2 code
}
}
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.
screen.exitonclick();
return 0;
Note: You might need to adjust your TurtleScreen’s size to capture all
of the output.
Sample Code
/**
* @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) {
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);
}
}
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;
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.
Expected Output
216
Expected Output
1
Learning Objectives: Classes and
Objects
Define a constructor
challenge
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.
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.
.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.
class Actor {
};
Naming classes
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.
Actor helen;
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.
class Actor {
public:
string first_name;
string last_name;
};
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.
Actor helen;
helen.first_name = "Helen";
helen.last_name = "Mirren";
cout << helen.first_name + ' ' + helen.last_name << 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
class Actor {
public:
string first_name;
string last_name;
string birthday;
int total_films;
int oscar_nominations;
int oscar_wins;
};
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.
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;
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.
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;
}
};
Actor helen;
cout << helen.first_name + ' ' + helen.last_name << endl;
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;
}
};
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.
Actor helen;
Actor tom;
cout << helen.first_name << ' ' << helen.last_name << endl;
cout << tom.first_name << ' ' << tom.last_name << endl;
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;
}
};
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.
Code
Your code for the object representing Denzel Washington should look
something like this:
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;
You can update the attributes once the object has been instantiated if need
be.
helen.oscar_nominations = 4;
helen.oscar_wins = 1;
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?
class ComicBookCharacter {
public:
string name;
int age;
string type;
};
int main() {
ComicBookCharacter a;
a.name = "Calvin";
a.age = 6;
a.type = "human";
ComicBookCharacter b = a;
a.name = "Hobbes";
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
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;
};
Student andy;
andy.name = "Andy";
andy.ID = 123456;
andy.major = "Computer Science";
andy.GPA = 3.45;
andy.age = 22;
andy.YOG = 2021;
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;
}
};
int main() {
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;
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.
class Student {
public:
string name;
int ID;
string major;
double GPA;
int age;
int YOG;
int main() {
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;
return 0;
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.
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
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.
class Player {
public:
int health;
int score;
int level;
Player() {
health = 100;
score = 0;
level = 1;
}
};
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;
challenge
player1.health = 0;
cout << "This player has " << player1.health << " health.
Game over." << endl;
void PrintPlayer(Player p) {
cout << "This player has " << p.health << " health, a score of
" << p.score;
cout << ", and is on level " << p.level << "." << endl;
}
Player player1;
PrintPlayer(player1);
player1.health -= 10;
player1.score += 25;
player1.level += 1;
PrintPlayer(player1);
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.
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;
}
}
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);
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;
class Player {
public:
int health;
int score;
int level;
Player() {
health = 100;
score = 0;
level = 1;
}
};
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;
}
}
int main() {
Player player1;
PrintPlayer(player1);
player1.health = 0;
player1.score += 25;
player1.level += 1;
PrintPlayer(player1);
return 0;
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.
.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()).
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;
}
}
Player mario;
mario.PrintPlayer();
challenge
Player mario;
PrintPlayer(mario);
Player mario;
mario.PrintPlayer();
mario.ChangeHealth(25);
mario.NextLevel();
mario.PrintPlayer();
//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
class Meal {
private:
vector<string> drinks;
vector<string> appetizers;
vector<string> main_courses;
vector<string> desserts;
};
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;
};
Create a Meal object in main and then test your code with the following
added commands.
Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();
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.
Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();
dinner.AddAppetizer("bruschetta");
dinner.PrintAppetizers();
challenge
Meal code
#include <iostream>
#include <vector>
using namespace std;
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;
};
int main() {
Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();
dinner.AddAppetizer("bruschetta");
dinner.PrintAppetizers();
dinner.AddMainCourse("roast chicken");
dinner.PrintMainCourses();
dinner.AddDessert("chocolate cake");
dinner.PrintDesserts();
return 0;
}
Printing the Meal
#include <iostream>
#include <vector>
using namespace std;
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;
};
int main() {
Meal dinner;
dinner.AddDrink("water");
dinner.PrintDrinks();
dinner.AddAppetizer("bruschetta");
dinner.PrintAppetizers();
dinner.AddMainCourse("roast chicken");
dinner.PrintMainCourses();
dinner.AddDessert("chocolate cake");
dinner.PrintDesserts();
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:
Drinks: None
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.
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();
Expected Output
Sample Code
#include <iostream>
#include <vector>
using namespace std;
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;
};
int 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();
return 0;
}
Lab 1
Lab 1
For this lab, you will create a Student class that has the following private
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.
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;
};
In main, try a few test cases to see if StudentStatus updates alice’s grade
level correctly.
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.
class Student {
public:
Student() {
name;
grade;
}
public:
string name = "Alice";
int grade = 4;
int score = 65;
};
Because the code above has public class attributes, the following code in
main can change those attributes’ values directly.
Student steve;
steve.name = "Steve";
cout << steve.name << endl;
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;
};
Student steve;
steve.name = "Steve";
cout << steve.name << endl;
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;
};
Student steve;
steve.ChangeName("Steve");
cout << steve.ReturnName() << endl;
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.
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
};
DO NOT CHANGE the existing code in main or you will not pass the test:
250
40
birds
324
168
big cats
Learning Objectives
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;
};
ExampleClass my_example;
my_example.SetN(5, 7);
my_example.Describe();
cout << my_example.Sum() << endl;
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.
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.
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;
};
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;
challenge
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.
class Phone {
public:
Phone(string mo, int st, int me) {
model = mo;
storage = st;
megapixels = me;
}
string model;
int storage;
int megapixels;
};
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.
class Phone {
public:
Phone(string mo, int st, int me) {
model = mo;
storage = st;
megapixels = me;
}
private:
string model;
int storage;
int megapixels;
};
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;
};
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.
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;
}
};
PrivateExample my_example(5);
my_example.PrivateFunction();
PrivateExample my_example(5);
my_example.PublicFunction();
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;
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;
string s = "house";
Words vowels(s, s.length());
vowels.Printer();
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.
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;
};
challenge
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
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.
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 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.
Possible Solution
//class definitions
public:
void SetStorage(int new_storage) {
storage = new_storage;
}
//main function
my_phone.SetStorage(128);
cout << my_phone.GetStorage() << endl;
my_phone.SetMegapixels(6);
cout << my_phone.GetMegapixels() << endl;
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.
class Person {
public :
Person(string n, int a) {
name = n;
age = a;
}
string GetName() {
return name;
}
int GetAge() {
return age;
}
private:
string name;
int age;
};
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.
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.
Possible Solution
Add data validation to the SetName function so that all strings with
one or more characters are valid.
Possible Solution
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.
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;
};
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:
Full Code
#include <iostream>
#include <vector>
using namespace std;
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;
int main() {
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;
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;
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;
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;
int main() {
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.
Updated Code
#include <iostream>
#include <vector>
using namespace std;
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 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;
int main() {
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;
int main() {
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
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
};
Now declare an instance of the Superhero class and print the value of the
name and age attributes using their getter functions.
Superhero s;
cout << s.GetName() << endl;
cout << s.GetAge() << endl;
Solution
Superhero s;
s.SetName("Peter Parker");
s.SetOccupation("Student");
cout << s.GetOccupation() << endl;
s.SayHello();
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.
Source: https://www.programiz.com/cpp-programming/public-protected-
private-inheritance
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
.guides/img/inheritance/AccessModifierTable
Source: https://www.tutorialspoint.com/cplusplus/cpp_inheritance.htm
private:
string s_derived;
};
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.
string s_main;
Derived dc;
dc.ReturnPublic(s_main);
The reason why main is able to call ReturnPublic is due to the fact that
ReturnPublic is a public member function within Derived.
challenge
private:
string s_derived;
};
void ReturnProtected(string s) {
Protected(s_derived); //protected function inherited from
Base
}
private:
string s_derived;
};
string s_main;
Derived dc;
dc.ReturnProtected(s_main);
dc.Public(s_main);
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
void ReturnProtected(string s) {
Protected(s_derived);
}
private:
string s_derived;
};
string s_main;
Derived dc;
dc.ReturnProtected(s_main);
dc.Public(s_main);
void ReturnProtected(string s) {
Protected(s_derived);
}
/*protected:
void Public(string s) { (inherited as protected from Base)
s = "public";
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;
};
//protected:
//int y;
};
class Base {
public:
int x;
protected:
int y;
private:
int z;
};
protected:
int y;
private:
int z;
};
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
Sample Code:
Constructor2(Param p1, Param p2) : Constructor1(p1, p2) {}
Here is an example:
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.
Superhero s;
cout << "s is of type: " << typeid(s).name() << endl;
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;
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.
class Person {
public:
void Greeting() {
cout << "I'm a Person" << endl;
}
};
class Animal {
public:
void Greeting() {
cout << "I'm an Animal" << endl;
}
};
void Substitution(Person p) {
p.Greeting();
}
Superhero s;
Substitution(s);
challenge
Animal a;
Substitution(a);
void Substitution(Superhero s) {
s.Greeting();
}
Person p;
Substitution(p);
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.
class Person {
public:
void Greeting() {
cout << "I'm a Person" << endl;
}
};
See what happens when you you revise the Substitution function and main
to look like below:
void Substitution(Person p) {
p.Greeting();
}
Superhero s;
Substitution(s);
Hero h;
Substitution(h);
.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
string GetSecretIdentity() {
return secret_identity;
}
private:
string secret_identity;
};
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.
string GetSecretIdentity() {
return secret_identity;
}
string GetNemesis() {
return nemesis;
}
private:
string secret_identity;
string nemesis;
};
int main() {
//add code below this line
return 0;
string GetSecretIdentity() {
return secret_identity;
}
string GetNemesis() {
return nemesis;
}
void RevealSecretIdentity() {
cout << "My real name is " << secret_identity << '.' <<
endl;
}
private:
string secret_identity;
string nemesis;
};
string GetSecretIdentity() {
return secret_identity;
}
string GetNemesis() {
return 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;
};
int main() {
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.
void SayHello() {
cout << "My name is " << GetName() << ", and criminals
fear me." << endl;
}
void SayAge() {
cout << "Age is just a number." << endl;
}
void SayHello() {
cout << "My name is " << GetName() << ", and criminals
fear me." << endl;
}
void SayAge() {
cout << "Age is just a number." << endl;
}
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
void SayHello() {
cout << "Hello, my name is " << name << '.' << endl;
}
void SayAge() {
cout << "I am " << age << " years old." << endl;
}
to
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.
challenge
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.
ClassC c;
c.Bonjour();
c.ClassB::Hello();
c.ClassA::Hello();
void AuRevoir() {
cout << "Au revoir" << endl;
}
};
int main() {
ClassC c;
c.AuRevoir();
return 0;
ClassC c;
c.Hello();
c.ClassB::Hello();
c.ClassA::Hello();
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
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;
};
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();
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;
};
int GetWidth() {
return width;
}
void DrawBox() {
for (int i = 0; i < width; i++) {
DrawLine();
}
}
private:
int width;
};
challenge
Given Code
#include <iostream>
using namespace std;
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;
};
void DrawBox() {
for (int i = 0; i < width; i++) {
DrawLine();
}
}
private:
int width;
};
int main() {
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.
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;
};
int GetWidth() {
return width;
}
void DrawBox() {
for (int i = 0; i < width; i++) {
DrawLine();
}
}
private:
int width;
};
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;
}
}
}
};
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!
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:
Given Code
#include <iostream>
using namespace std;
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;
}
int GetLength() {
return length;
}
string GetGenre() {
return genre;
}
string GetAlbum() {
return album;
}
string GetArtist() {
return artist;
}
private:
string title;
int length;
string genre;
string album;
string artist;
};
int main() {
return 0;
Expected Output
Overload a function
Override a function
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.
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;
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
int a = 5;
string b = "true";
cout << (a + b) << endl;
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;
}
};
Alpha test_object;
test_object.Show();
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
Solution
class Alpha {
public:
void Show() {
cout << "I am from class Alpha" << endl;
}
void Hello() {
cout << "Hello from Alpha" << endl;
}
};
void Hello() {
cout << "Hello from Bravo" << endl;
}
};
int main() {
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.
class TestClass {
public:
int Sum(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
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.
TestClass tc;
cout << tc.Sum(1, 2, 3) << endl;
cout << tc.Sum(1, 2) << endl;
challenge
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 main() {
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;
return 0;
class Person {
public:
Person() {}
string Info() {
return (name + " lives at " + to_string(number) + ' ' +
street + '.');
}
private:
string name;
int number;
string street;
};
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.
Person p1;
Person p2("Calvin", 37, "Main Street");
cout << p1.Info() << endl;
cout << p2.Info() << endl;
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
class Person {
public:
//Person() {}
string Info() {
return (name + " lives at " + to_string(number) + " "
+ street + ".");
}
private:
string name;
int number;
string street;
};
Person p1;
//Person p2("Calvin", 37, "Main Street");
cout << p1.Info() << endl;
//cout << p2.Info() << endl;
class Person {
public:
//Person() {}
string Info() {
return (name + " lives at " + to_string(number) + " "
+ street + ".");
}
private:
string name;
int number;
string street;
};
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.
class Shape {
public:
virtual double Area() = 0;
};
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.
class Shape {
public:
virtual double Area() = 0;
double GetBase() {
return base;
}
double GetHeight() {
return height;
}
protected:
double base;
double height;
};
double Area() {
return base * height / 2;
}
};
double Area() {
return base * height;
}
};
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.
As expected, the code returns the correct calculations for the Triangle and
Rectangle objects.
challenge
Shape s;
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.
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.
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};
void AddInfo() {
}
};
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.
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 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;
};
void DisplayInfo() {
void AddInfo() {
void ShowList() {
Contacts contacts;
contacts.Display();
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
#include <iostream>
#include <vector>
using namespace std;
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};
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();
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.
#include <iostream>
#include <vector>
using namespace std;
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 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(){
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();
}
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);
Contacts contacts;
contacts.Display();
cout<< contacts.GetLength()<< endl;
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]
Code
#include <iostream>
#include <vector>
using namespace std;
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};
void DisplayInfo() {
void AddInfo() {
cout << endl;
string sc2;
cout << ("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);
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;
};
int main(){
Contacts contacts;
contacts.Display();
cout << contacts.GetLength() << endl;
return 0;
}
Lab 3
#include <iostream>
#include <vector>
using namespace std;
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};
void DisplayInfo() {
void AddInfo() {
cout << endl;
string sc2;
cout << ("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);
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;
};
Contacts contacts;
contacts.Display();
cout << contacts.GetLength() << endl;
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:
Contacts contacts;
contacts.Display();
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 = "";
}
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;
}
}
.guides/img/Polymorphism/lab3_pic1
Thomas Hobbes
555 666-7777
[email protected]
Philosopher
555 888-9999
[email protected]
.guides/img/Polymorphism/lab3_pic2
Code
#include <iostream>
#include <vector>
using namespace std;
//add class definitions below this line
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};
void DisplayInfo() {
void AddInfo() {
cout << endl;
string sc2;
cout << ("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);
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;
}
}
};
int main(){
Contacts contacts;
contacts.Display();
return 0;
}
Lab 4
#include <iostream>
#include <vector>
using namespace std;
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 0;
};
void DisplayInfo() {
void AddInfo() {
cout<< endl;
string sc2;
cout<<("Enter their name: ");
getline(cin >> ws, sc2);
string name = sc2;
names.push_back(name);
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;
}
}
};
int main(){
Contacts contacts;
contacts.Display();
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();
}
Code
#include <iostream>
#include <vector>
using namespace std;
class Information {
public:
virtual void DisplayInfo() = 0;
virtual void AddInfo() = 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);
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;
}
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;
}
}
};
int main(){
Contacts contacts;
contacts.Display();
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;
class Chef {
public:
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;
};
int main() {
c1.Display();
c2.Display();
c3.Display();
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:
Compare objects
Using #include
.guides/img/advanced/Include
#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:
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.
.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() {
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
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
};
int main() {
Player mario;
mario.PrintLevel(); //calling class function, object required
cout << Player::ChangeLevel(5) << endl; //calling static
function, object not needed
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;
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;
};
int main() {
Player mario;
mario.PrintLevel();
cout << Player::ChangeLevel(6) << endl;
Player luigi;
luigi.PrintLevel();
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
struct Person {
string name;
int age;
double salary;
};
int main() {
Person p;
p.age = 50;
cout << p.age << endl;
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.
int main() {
grades grade;
grade = A;
cout << "Grade = " << grade << endl;
return 0;
NOTE: Enum values must be integers. For example, you can’t create an
enum with string values.
challenge
class Player {
public:
Player() {
health = 100;
score = 0;
level = 1;
}
private:
int health;
int score;
int level;
};
int main() {
Player mario;
Player luigi;
cout << boolalpha;
cout << (typeid(mario) == typeid(luigi)) << endl;
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.
class Player {
public:
Player() {
health = 100;
score = 0;
level = 1;
}
void NextLevel() {
level++;
}
private:
int health;
int score;
int level;
};
Player mario;
Player luigi;
cout << boolalpha;
cout << Player::ComparePlayers(mario, luigi) << endl;
return 0;
challenge
Player mario;
Player luigi;
cout << boolalpha;
mario.NextLevel();
cout << Player::ComparePlayers(mario, luigi) << endl;
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() {
return 0;
header
#ifndef CLASS_H
#define CLASS_H
#include <iostream>
using namespace std;
class Greeting {
public:
Greeting(string g) {
greeting = g;
}
string GetGreeting() {
return greeting;
}
void PrintGreeting(){
cout << GetGreeting() << endl;
}
private:
string greeting;
};
#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.
Lab 2
You are provided the following header and main files:
point.h
#ifndef SLOPE_H
#define SLOPE_H
#endif
slope.h
#ifndef SLOPE_H
#define SLOPE_H
#endif
lab2.cpp
#include <iostream>
using namespace std;
#include "point.h"
#include "slope.h"
int main() {
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.
struct point {
int x;
int y;
};
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) );
}
};
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.
point a;
point b;
a.x = 0;
a.y = 0;
b.x = 2;
b.y = 2;
cout << Slope::CalculateSlope(a, b) << endl;
challenge
point a;
point b;
a.x = 1;
a.y = 2;
b.x = 10;
b.y = 20;
cout << Slope::CalculateSlope(a, b) << endl;
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() {
point a;
point b;
a.x = 1;
a.y = 2;
b.x = 10;
b.y = 20;
cout << Slope::CalculateSlope(a, b) << endl;
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;
int main() {
BankAccount account1;
account1.checking = 2432;
account1.savings = 89.52;
BankAccount account2;
account2.checking = 1998;
account2.savings = 239.43;
account1.ToString();
account2.ToString();
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.
BankAccount account1;
account1.checking = 2432;
account1.savings = 89.52;
BankAccount account2;
account2.checking = 1998;
account2.savings = 239.43;
account1.ToString();
account2.ToString();
Expected Result
BankAccount[checking=2432.00, savings=89.52]
BankAccount[checking=1998.00, savings=239.43]