What We Will Cover
Continuations
Homework Questions?
Ensuring Registration Priority for Next Semester
Higher priority registration helps you get the classes you want. To improve your registration priority:
Begin an education plan in WebAdvisor's Student Planning tool
Declare an active program/major
Have good academic standing
Homework Questions?
Where do you place function comment blocks?
^ top
9.1: Reviewing Functions
Learner Outcomes
At the end of the lesson the student will be able to:
Define and call functions
Describe the difference between parameters and arguments
Identify the scope of a variable
Write function declarations (prototypes)
Describe function style requirements
Design a program with functions
^ top
9.1.1: Defining and Calling Functions
As we add more code to programs, main()
becomes too long to easily understand
The solution is to break up the long sequences of code into shorter sections using functions
Functions are a way to organize programs into modules
With functions, we can potentially reduce the size of our code by collecting duplicate code into one place
In addition, we can reuse well-written functions in other programs, saving us from rewriting code
Defining Functions
When we reuse a block of code in various parts of a program, we should put the code into a function
To define a function, we use the following syntax:
returnType functionName (parameter1 , ..., parametern ) {
statements
}
Where:
returnType : the data type of the value returned
functionName : the name you make up for the method
parameterx : the input values of the function, if any
statements : the statements to execute when calling the function
If the function does not return a value, we use the return type: void
Otherwise, we specify the type of data we want to return
As an example, we wrote the function:
int add(int a, int b) {
int sum = a + b;
return sum;
}
The add()
function returns an integer value as shown by the return value: int
Functions returning a value use a return
statement
return sum;
A return statements ends a function call and returns a value specified after the word return
For a void function, we code nothing after the word return, like
return;
Return statements are optional for void
functions
A void function returns automatically after reaching its last line
Function Calls
When we define a function, the code does not execute automatically
To execute the code, we must call a functions call like:
int sum = add(32, 10);
When we call a function, we specify its name and provide arguments for each parameter
The flow of the program execution stops and jumps to the called function
When the called function finishes executing it returns
The calling code continues by executing the next operation
Check Yourself
The following code snippet displays the value ________ .
int fun() {
return 12;
}
// other code here
cout << fun();
Which of the following is a function definition and which is a function call?
add(32, 10);
int add(int a, int b) { /* statements */ }
The best return type for a function with the following return statement is ________ .
return 42.3;
^ top
9.1.2: Parameters and Scope
Scope and Variables
Scope is the term used to define where a program can access a variable
A variable declared inside a pair of curly braces is local to that block of code
Blocks begin at an opening brace ({) and end at a closing brace (})
Because of scope, we can use variables with the same name in different functions
However, even if the name is the same the variable is a different memory location
Parameter Passing Mechanisms
C++ can pass arguments to parameters in the following ways:
Because value parameters send a copy of an arguments value, change to parameters have no effect on the argument
int mystery(int param)
However, reference parameters send a variable address and thus changes to the parameter changes the value of the argument variable
int mystery(int& param)
The following animation shows the effect of call-by-reference versus call-by-value
Call-by-value is like calling on a phone to get something done
Call-by-reference is like going somewhere to get something done
When you return from call-by-reference you can bring something back like a cup of coffee
Image source: penjee.com
Check Yourself
The following code displays the value ________ .
int fun(int param) {
param = 12;
return param;
}
// main code here
int x = 42;
fun(x);
cout << x;
The following code displays the value ________ .
int fun(int& param) {
param = 12;
return param;
}
// main code here
int x = 42;
fun(x);
cout << x;
The following code displays the value ________ .
int fun(int& param) {
param = 12;
return param;
}
// main code here
int x = 42;
cout << fun(x);
^ top
Exercise 9.1: Returning Multiple Values (6m )
In this exercise we write a function that returns two values.
Specifications
Copy the following program into a text editor, save it as coffee.cpp
, and then compile and run the starter program to make sure you copied it correctly.
#include <iostream>
using namespace std;
// Define function here
int main() {
return 0;
}
Before main()
, add the following function to fill a cup of coffee:
void fillCup(double cup, string sweetener) {
cup = 10;
sweetener = "sugar";
cout << "Coffee amount: " << cup << " oz.\n";
cout << "Sweetener: " << sweetener << endl;
}
Compile your code to make sure you copied it correctly.
Inside the main()
function, add these statements:
double cup = 0;
string sweetener = "none";
fillCup(cup, sweetener);
if (cup == 0) {
cout << "Where's my coffee?\n";
} else {
cout << cup << "oz. coffee and " << sweetener << " too!\n";
cout << "Time to shine!\n";
}
Compile and run your code. What do you see when you run the code? (click here to verify)
Coffee amount: 10 ounces
Sweetener: sugar
Where's my coffee?
Update your code to call fillCup()
by reference for BOTH parameters.
After changing to call-by-reference, what do you see when you run the code? (click here to verify)
Coffee amount: 10 ounces
Sweetener: sugar
10oz. coffee and sugar too!
Time to shine!
Save your coffee.cpp file to submit to Canvas as part of assignment 9 .
When finished, verify your code with a classmate. Then please help those around you as needed.
Exercise Questions
What was the effect of changing from call-by-value to call-by reference?
How many values did you return from the fillCup()
function?
^ top
9.1.3: Prototypes, Style and Design
C++ allows you to declare functions without defining them
Function declarations (prototypes) have the function heading without the function body
The general syntax for declaring a function is:
returnType functionName (parameter1 , ..., parametern );
For example:
double square(double number);
Prototypes end with a semicolon (;
) rather than curly braces
By declaring prototypes before main()
you can define the functions after main()
Function Style
Functions have style requirements we must follow
For instance, we must have a block comment before the name
Functions have naming conventions similar to variable names: camel case or underbars
When making up a name for a function, use verbs since functions perform an action
We indent functions statements inside curly braces, like elsewhere in our code
Function Design
We write functions in our code for these reasons:
To organize our code into modules
To reduce repeated code
To allow for code reuse in another program
To develop a program around functions we use stepwise refinement (aka top-down design or functional decomposition )
With stepwise refinement we create our programs or algorithms with the process:
Describe general tasks
Break each task into smaller tasks as needed
Continue to refine in successive steps until the whole program is fully defined
Eventually, the tasks are so trivial they are easy to code
General tasks and common code are organized into functions
^ top
9.2: Introduction to Object-Oriented Programming
Learner Outcomes
At the end of the lesson the student will be able to:
Describe objects and classes
Write class declarations that define interfaces
Code member variables and member functions
Design and implement accessor and mutator member functions
Write simple no-argument constructors
Declare a class and use it to create an object
Call a member function of an object to perform a task
^ top
9.2.1: About Objects and Classes
We have learned to structure programs using functions
While this is a good practice, experience shows it does not go far enough
As programs become larger, it becomes difficult to maintain a large collection of functions
To overcome this problem, computer scientists developed object-oriented programming (OOP)
In object-oriented programming code is centered around objects instead of functions
For example, consider a complex object like a car:
Do we think of a car as a collection of parts?
Or do we think of a car as an object?
Moving to Object-Oriented Programming
Some Object-Oriented Concepts
Most often functions work on a certain type or group of data
For example, a program about cars may have variables for names and prices
Functions for a car work with these variables
Thus we group, or encapsulate , the variables for names and prices with their functions
When we encapsulate related variables and functions in C++, we call these groupings objects
Some object terminology:
member variables : variables grouped inside an object (aka data members )
member functions : functions grouped inside an object that work with data members
Designing Objects
When we design objects in C++, we do not design a single object
Instead we design a class for creating one or more objects
A class is a a user defined type that provides a template for creating objects
A class specifies the components and operations of an object
We discuss how to declare a class for creating objects in the following section
The Difference Between Classes and Objects
What is the difference between a class and an object?
A class is a template for building modules
An object is one of the modules built from the template
By analogy, a class is like the factory that makes cars
We need to build the car in the factory before we can use the object
Other analogies may help understanding:
Blueprint and house : a class is a blueprint and the house is made following the blueprint
Dog and Fido : a class is like the concept of a dog and objects are individual animals like Fido.
Cookie cutter and cookies : a class is like a cookie cutter and objects are like cookies
Mold and Pots : a class is like a mold and objects are the clay pots coming out of the mold.
Stencil and drawings : a class is like stencil and objects are the drawings made from the stencil.
3D printers and objects : a class is like a 3D printer program and objects are the items printed
For the above analogies, which is the class and which is the object?
Check Yourself
A bundle or group of related variables and functions in known as a(n) ________ .
When we design objects in C++, we write a(n) ________ .
For the following code, the item that is not an object is ________ .
cin
cout
int
string str
^ top
9.2.2: Class Declarations
Let us look at how to develop classes in C++
To develop a class we start by declaring a class using the syntax shown below
Within the class declaration, we both:
Declare (prototype) the member functions that specify the behavior
Declare the data members to hold the object's data
The
After the class declaration we implement the member functions by writing the statements for the body of the functions
Class Declaration Syntax
Example Class Definition
Private Members and Information Hiding
Note the keywords public
and private
These keywords are known as access modifiers
The keyword public
means that the following members have no restrictions and are "available to the public" (other parts of the program)
The keyword private
restricts access to only member functions
An access modifier is how we implement information hiding in a class
Information hiding is restricting access to certain data and code
By restricting access we are able to make changes to the "hidden" parts of the program without affecting the rest of the program
Setting private
accessibility for all data is good design practice
This protects data by forcing indirect access only through public
functions
We then add code to the public functions to ensure that the data cannot accidentally be put into an incorrect state
In general, we declare most class functions public
The example program below contains a class declaration and compiles but does not do anything useful
We will discuss the other pieces we must add to make the program do something useful in the following sections
Example Program with a Class Declaration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
class Product
{
public:
void read();
void print() const;
private:
string name;
double price;
};
// For testing
int main()
{
// Construct objects here
return 0;
}
Programming Style: Class Naming Conventions
Use nouns to name classes -- they represent objects
Start all class names with a capital letter
The capital letter differentiates class names from variable names
Spell class names using CamelCase where each "word" starts with an uppercase letter
What would be an appropriate class name for the picture? (answer )
Try It: Declare a Class (4m )
Copy the following program into a text editor, save it as car.cpp
, and then compile and run the starter program to make sure you copied it correctly.
#include <iostream>
using namespace std;
// Declare class here
int main() {
// Construct objects here
return 0;
}
Declare a class named Car
, and then compile your code to check for syntax errors.
Remember the semicolon after the closing curly brace.
Declare private member variables for a name , price and mpg (miles per gallon) with the appropriate data types.
Declare two public prototypes for functions named read()
and print()
with void return types and no parameters.
Compile and run the modified program to make sure you made the changes correctly.
Save your source code file as we will be adding to it in the next Try It.
When finished, please help those around you.
Check Yourself
The public
parts of a class declaration describes what operations can be performed on the class and is known as the programming ________ .
To allow only member functions and constructors of an object to access a member variable, use the keyword ________ .
True or false : good programming practice is to set the accessibility of all member variables to private
.
True or false : the main reason to set all member variables to private is to allow changes to how the class data is stored.
As a matter of style, class names should be spelled using ________ .
^ top
9.2.3: Data Members and Objects
Constructing an Object
After defining a class, we construct one or more objects
Objects are then a particular instance of a class, meaning an object has particular values
The syntax for constructing an object is:
ClassName objectName ;
or
ClassName objectName = ClassName ();
Where:
ClassName : the name of the class type
objectName : the variable of the class type
For example, to construct a Product
object named milk
and another named bread
:
Product milk;
Product bread = Product();
When we construct a Product
object the program allocates memory like:
space for name
space for price
Memory is allocated for both variables next to each other in memory
The amount of memory allocated depends on the data type of each member variable
Since the data members are declared private
, we cannot access the variables directly
cout << milk.name << endl; // Error -- use member function instead
Instead, we must call member functions which we cover in the next section
Dot Notation
Try It: Construct an Object (2m )
Open your source code file from the last Try It .
In the main()
function, define a Car
object (Car
class variable) like:
int main() {
Car tesla;
return 0;
}
Compile and run your code to verify it works correctly.
If you have questions or problems, ask a classmate or the instructor for help.
Save your source code file as we will be adding to it in the next Try It.
What does defining and compiling a Car
variable tell us about class and objects?
When finished, please help those around you.
Check Yourself
Of the following, the code that correctly constructs an object for the class Person
is ________ .
Person bruce;
Person bruce();
string bruce;
bruce is a Person;
True or false : when an object is constructed, C++ sets aside memory for all the member variables automatically.
True or false : every object has separate memory space for its member variables.
^ top
9.2.4: Member Functions
Member Function Definition Syntax
The general syntax for implementing a function declared inside a class is:
returnType ClassName ::functionName (parameter1 , ..., parametern ) [const] {
statements
}
Where:
returnType : the type of the value returned
ClassName : the name of the class
functionName : the name you make up for the function
parameterx : the input values, if any
statements : the statements to execute when the function is called
Note that the square brackets indicate that const
is optional
We implement member functions like we implement other functions
The only difference is we must put ClassName ::
in front of the function name
Where ClassName is the name of our class
The ClassName ::
prefix tells the compiler we are defining a member function for that class
For example, we could implement the read()
function like this:
void Product:: read() {
cout << "Enter a product name: ";
cin >> ws;
getline(cin, name);
cout << "Enter the price for a " << name << ": ";
cin >> price;
}
We may have other read()
functions and we must tell the compiler this one belongs to a particular class
The compiler will match the function declaration (prototype) in the class with the function definition (implementation )
Notice that our function tests the data as it is entered to verify it is correct
Verification of data is one benefit of hiding member variables
Where are the variables name
and price
declared? (answer )
Mutator Functions
The read()
function above is a mutator function - a function that modifies one or more member variables
When the value of a member variable changes, we say its state has changed
After a mutator function runs, the state of the class changes (mutates)
In this case, the read()
function changes the values of all the member variables
As an example, if an objects starts with member variables in the following state:
If the user enters "Milk" and 3.95
when the read()
function is called, the member variables would contain:
name = "Milk"
price = 3.95
Accessor Functions
Member Functions Calling Member Functions
Try It: Add Member Functions (4m )
Open your source code file from the last Try It .
After the class declaration, add the implementation of the mutator function read()
that asks for the name , price and mpg of a car.
Compile your code to verify you wrote it correctly.
After the class declaration, add the definition of the accessor function print()
that prints the name, price and mpg of a car object.
Compile your code to verify you wrote it correctly.
Change the main()
function to call the member functions like:
int main() {
Car tesla;
tesla.read();
tesla.print();
return 0;
}
Compile and run your code to verify it works correctly.
If you have questions or problems, ask a classmate or the instructor for help.
You program should work like this:
Enter the name of the car: Civic
Enter the price for a Civic: 19500
Enter the MPG for a Civic: 31
Civic @ 19500 with MPG: 31
Save your source code file as we will be adding to it in the next Try It.
When finished, please help those around you.
Check Yourself
A function declared inside a class is known as a ________ function.
A valid first line of a member function definition is ________ .
void print()
void Person::print() const
Person::print()
Person::void print() const
A function that can modify an object is known as a(n) ________ function.
A C++ standard for accessor functions is to include in the function header the keyword ________ .
True or false : member variables can always be accessed by member functions, even when declared private
.
^ top
9.2.5: Coding Constructors
Adding a Constructor
Example Program with a Constructor Added
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
using namespace std;
class Product {
public:
Product();
void read();
void print() const;
private:
string name;
double price;
};
Product::Product() {
name = "none";
price = 0.0;
}
void Product::read() {
cout << "Enter the name of the product: ";
cin >> ws;
getline(cin, name);
cout << "Enter the price for a " << name << ": ";
cin >> price;
}
void Product::print() const {
cout << name << " @ " << price << endl;
}
// For testing
int main() {
Product milk;
Product bread;
cout << "Enter the milk product data\n";
milk.read();
cout << "\nEnter the bread product data\n";
bread.read();
milk.print();
bread.print();
return 0;
}
In-class Member Initializers
Check Yourself
True or false : when a variable is not assigned a value in C++, its value is automatically set to zero (0).
True or false : the purpose of a constructor is to initialize all the member variables.
True or false : a constructor has the same name as the class.
True or false : the return type of a constructor is always void
.
More Information
^ top
Exercise 9.2: Creating a Class (5m )
In this exercise we add a constructor to our exercise.
Specifications
Complete the Try It activities we explored throughout the section including:
Try It: Declare a Class
Try It: Construct an Object
Try It: Add Member Functions
Open your source code file from the last Try It .
In main()
, add a call to the member function print()
function before the call to the member function read()
, like:
int main() {
Car tesla;
tesla.print();
tesla.read();
tesla.print();
return 0;
}
Compile and run your program and notice the output of member function print()
before calling read()
. It should look something like:
@ 2.32211e-322 with MPG: 6.89746e-308
Enter the name of the car: Civic
Enter the price for a Civic: 19500
Enter the MPG for a Civic: 31
Civic @ 19500 with MPG: 31
User input is shown in italics for the example only, NOT your program. Notice that before calling read()
, the print()
function shows garbage output. After calling read()
, the output is correct. Why do you think the first call to print()
produces garbage output?
Because the member variables name
, price
and mpg
have NOT been initialized.
Add a constructor declaration to the class specification. Your class structure should now look like:
class Car {
public:
Car();
void read();
void print() const;
private:
string name;
double price;
double mpg;
};
After the class declaration,, add the following constructor definition.
Car::Car() {
name = "none";
price = 0;
mpg = 0;
}
Compile and run your program and notice the output of member function print()
before calling read()
. It should look like:
none @ 0 with MPG: 0
Enter the name of the car: Civic
Enter the price for a Civic: 19500
Enter the MPG for a Civic: 31
Civic @ 19500 with MPG: 31
User input is shown in italics for the example only, NOT in your program. Notice that calling the print()
function before read()
now shows the default values assigned by the constructor.
Save your source code file to submit as part of assignment 9.
When finished, please help those around you.
^ top
9.2.6: Summary
We have learned to structure programs using functions
While this is a good practice, experience shows it does not go far enough
As programs become larger, it becomes difficult to maintain a large collection of functions
To overcome this problem, computer scientists developed object-oriented programming (OOP)
In object-oriented programming code is centered around objects instead of functions
We encapsulate variables and functions into an object
The variables inside an object are known as member variables (aka data members )
The functions inside an object are known as member functions
When we design objects in C++, we do not design a single object
Instead we design a class for creating many objects
Defining a Class
Constructing an Object
Member Functions
Constructor Functions
^ top
9.3: Improving Our Class
Learner Outcomes
At the end of the lesson the student will be able to:
Write constructors with parameters
Overload constructors
Construct objects from classes with overloaded constructors
Discuss when to use accessor and mutator functions
Describe how to prevent "shadowing"
^ top
9.3.1: Constructors with Parameters
Recall that the purpose of a constructor is to initialize all member variables for an object to a valid state
Whenever we create an object, we need to assign specific values to the member variables
So far, we have been assigning specific values using a read()
member function
However, sometimes we want to create objects and assign them initial values without getting user input
For instance, we may want to predefine some objects or assign them values from another source such as a file or database
To accomplish this, we can write a constructor with parameters
For instance, we could add the following constructor prototype to the interface of our Product
class:
Product(string newName, double newPrice);
Also, we could define our constructor like this:
Product::Product(string newName, double newPrice) {
name = newName;
price = newPrice;
}
Check Yourself
True or false : The purpose of a constructor is to initialize all the member variables for an object.
True or false : we can assign a value to a member variable when we declare it, like:
class Product {
// ... other code omitted
private:
price = 0.0;
A constructor with no parameters is known as a ________ constructor because if assigns default values to member variables.
A class is a ________ for building objects.
True or false : constructors cannot have parameters, unlike functions.
True or false : constructors may assign a parameter to a member variable.
^ top
9.3.2: Multiple Constructors
Example: Default Constructor (No Parameters)
Example: Constructor Definition with one Parameter
Example: Constructor Definition with two Parameters
Implicit Default Constructors
If the programmer does not define any constructor, then the compiler supplies an empty default constructor like the following:
Product::Product() { }
However, if the programmer defines any constructor, the compiler does not supply a default constructor
Check Yourself
For any class, you can define ________ constructors.
1
2
3
as many as you need
A constructor with no parameters that sets the member variables to default values is known as a ________ constructor.
True or false : if you do not write any constructors for a class, the compiler will add one to the compiled code.
^ top
9.3.3: Constructing Objects from Overloaded Constructors
If a class has more than one constructor, our program must decide which constructor to call
The way that C++ resolves which constructor to call is by matching the arguments to the parameter list
Constructor matching is done based on the number and types of the parameters
Also, the matching only works if the order is correct
For example, assume our class has the following three constructors:
Product();
Product(string newName);
Product(string newName, double newPrice);
Creating the following objects calls the indicated constructor:
Product milk; // first
Product bread("Rye Bread"); // second
Product cheese("Cheddar", 6.75); // third
Names play no role in matching, only the data type in the correct order
We can have regular functions with the same name as long as their parameters are different
Avoiding the No-Parameter Trap
Notice the difference in the number of parenthesis between the first object created and the others
The first statement calls the no-parameter constructor
Product milk;
Other statements call a different constructor
It is an error to call the no-parameter constructor like this:
Product milk2(); // wrong
However, the compiler will not catch the error!
It is legal syntax to declare a function like milk2()
with no parameters
Thus, you will not see the error until you try to use the function prototype as an object
milk2.print(); // causes error
Another way to construct an object with a no-parameter constructor is to use the alternate form we discussed in section 9.2.5
For example, to construct a Product
object by calling the default constructor:
Product milk = Product();
Implicit Type Conversion
If there is no exact match for the parameters, C++ will look for compatible types
For instance, we can create the following object:
Product gouda("Gouda Cheese", 5);
Since '5
' is an int
, it does not exactly match the double
parameter of the constructor
However, C++ will automatically convert an int
to a double
and call the appropriate constructor
C++ only knows how to convert certain types, mostly the numeric types
Thus, C++ does not automatically convert something like a string
to a double
Thus, you cannot create a Product
object using:
Product gouda("Gouda Cheese", "5"); // wrong
Try It: Multiple Constructors and Their Objects (5m )
Open your source code file from the last exercise .
If you did not save the file then start with this file and save it as car.cpp
. Then compile and run the program to make sure you saved it correctly.
Add a constructor declaration with a three parameters to the class specification like the following:
Car(string newName, double newPrice, double newMpg);
After the class declaration, add a constructor definition (implementation) for the above constructor.
If you have questions or problems, ask a classmate or the instructor for help.
In main()
, construct an object using the overloaded constructor and then call print()
as follows:
cout << "Other cars for comparison:\n";
Car corolla("Toyota Corolla", 18500, 30);
corolla.print();
Compile and run your program and verify you see the car information printed like:
none @ 0 with MPG: 0
Enter the name of the car: Civic
Enter the price for a Civic: 19500
Enter the MPG for a Civic: 31
Civic @ 19500 with MPG: 31
Other cars for comparison:
Toyota Corolla @ 18500 with MPG: 30
User input is shown in italics for the example only, NOT in your program. If you have problems, ask a classmate or the instructor for help.
Identify which constructor is called for each object and add a comment in your source code where the object is created.
Save your car.cpp
file as we will add to it in the next exercise.
When finished please help those around you.
Check Yourself
C++ determines which constructor to call by matching the order of the parameter ________ .
Of the following, the wrong way to construct an object of class Person
is ________ .
Person bruce;
Person bruce();
Person bruce("Bruce");
Person bruce("Bruce", 39);
True or false : the following is a correct way to construct an object of class Person
.
Person bruce = Person();
^ top
9.3.4: Accessing Member Variables
Set Functions
The simplest mutator function is one that changes a single value
A common naming convention is to use the name of the value with the word set prepended
Thus to set the price of a Product
, we would add the following to our interface:
void setPrice(double newPrice);
We define our function like:
void Product::setPrice(double newPrice) {
price = newPrice;
}
To call a set-function from main()
we write code like:
Product milk;
milk.setPrice(3.99);
Get Functions
We often need to know the value of private
variables
For this we use public
functions to get the value of private
data
Called get -functions (a.k.a. accessor functions )
A common naming convention is to use the name of the value with the word get prepended
For example:
double Product::getPrice() const {
return price;
}
Remember that accessor functions should have the keyword const
as shown above
To call a get-function from main()
we write code like:
Product cheese("Cheddar", 6.75);
double priceCheese = cheese.getPrice();
cout << priceCheese << endl;
Example Class with Get and Set Functions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
using namespace std;
class Product {
public:
Product();
Product(string newName);
Product(string newName, double newPrice);
double getPrice() const;
void setPrice(double newPrice);
void read();
void print() const;
private:
string name;
double price;
};
Product::Product() {
name = "Unknown";
price = 0.0;
}
Product::Product(string newName) {
name = newName;
price = 0.0;
}
Product::Product(string newName, double newPrice) {
name = newName;
price = newPrice;
}
double Product::getPrice() const {
return price;
}
void Product::setPrice(double newPrice) {
price = newPrice;
}
void Product::read() {
cout << "Enter the name of the product: ";
cin >> ws;
getline(cin, name);
cout << "Enter the price for a " << name << ": ";
cin >> price;
}
void Product::print() const {
cout << name << " @ " << price << endl;
}
// For testing
int main() {
Product milk;
Product bread("Rye Bread");
bread.setPrice(2.99);
Product cheese("Cheddar", 6.75);
cout << "Enter the milk product data\n";
milk.read();
milk.print();
bread.print();
cheese.print();
double price = milk.getPrice();
cout << "The current price of milk is $" << price << endl;
cout << "Enter the new price: ";
double newPrice = 0;
cin >> newPrice;
milk.setPrice(newPrice);
milk.print();
return 0;
}
Designing Accessor and Mutator Functions
Not every member variable needs an accessor function
Also, not every variable needs a mutator function
In addition, not every get
-function needs a matching set
-function
Remember that the implementation details are hidden
Just because a class has member functions prepended with get
or set
does not necessarily explain how the class is designed
For example, a Time
class may have the following interface:
class Time {
public:
Time(int hour, int min, int sec);
Time();
int getHours() const;
int getMinutes() const;
int getSeconds() const;
int secondsFrom(Time t) const;
void addSeconds(int s);
private:
int timeInSecs;
};
Despite using hours, minutes and seconds in the public interface, all time values are stored as seconds:
Time::Time(int hour, int min, int sec) {
timeInSecs = 60 * 60 * hour + 60 * min + sec;
}
Then the accessor functions simply convert the seconds to hours, minutes and seconds as needed
int Time::getMinutes() const {
return (timeInSecs / 60) % 60;
}
Check Yourself
True or false : we should declare all member variables private
. Why?
True or false : the usual naming convention for get
or set
functions is to use the word "get" or "set" followed by the name of the value being returned.
True or false : every member variable must have a get- and set-function.
^ top
9.3.5: Local Variables, Parameters and Shadowing
Shadowing occurs when a local variable or parameter has the same name as a member variable of a class
Local variables and parameters with same name as a member variable "hide" the member variable
Any use of the variable's name will refer to the local variable or parameter
This is the source of many an elusive bug
We should not use the same name for a class member variable as a local variable or parameter
Remember that a parameter is a local variable, just initialized in a special way
Thus you should use a different name for a parameter and a member variable
In the following, which lines contain local shadowing and how do you correct the problem?
Example of Shadowing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;
class MyRectangle {
public:
MyRectangle();
MyRectangle(double length, double width);
void print();
private:
double length;
double width;
};
MyRectangle::MyRectangle() {
length = 0;
width = 0;
}
MyRectangle::MyRectangle(double length, double width) {
length = length;
width = width;
}
void MyRectangle::print() {
cout << "length: " << length << endl
<< "width: " << width << endl;
}
// For testing
int main() {
MyRectangle rec;
MyRectangle rec3x5(3.0, 5.0);
rec.print();
rec3x5.print();
return 0;
}
^ top
9.3.6: Some Style Requirements for Classes
Now that we know the basics of class syntax let us clarify some style requirements
Class names start with an upper-case letter and use uppercase letters as separators, like:
class MyClassName
Do not use underbars ('_')
Class variables and functions follow the same style we have been using
Start with a lower case letter
To separate words use either uppercase letters or underbars.
In addition, we continue to indent inside braces { }
like:
class Product {
public:
Product();
Product(string newName, double newPrice);
double getPrice() const;
void setPrice(double newPrice);
private:
string name;
double price;
};
In addition, we continue to place comment blocks before the function prototype like:
class Product {
public:
/**
Default constructor sets default values to member variables.
*/
Product();
/**
Constructor sets the current time.
@param newName The name of this product.
@param newPrice The price of this product.
*/
Product(string newName, double newPrice);
/**
Returns the current price of this product.
@return the current price.
*/
double getPrice() const;
// ... other code ommitted
/**
Sets a new price for this product.
@param newPrice The new price.
*/
void setPrice(double newPrice);
private:
int timeInSecs;
};
^ top
Exercise 9.3: Building A Better Class (15m )
In this exercise we explore the use of more features to improve our class.
Specifications
Open your source code file from the last Try It .
Add another constructor prototype with a two parameters to the class declaration like the following:
Car(string newName, double newPrice);
Implement the new constructor assigning the two parameters to name
and price
and 10
to mpg
.
In main()
, construct an object using the two-parameter constructor and then call print()
as follows:
cout << "Other car comparisons:\n";
Car corolla("Toyota Corolla", 18500, 30); // 3-param constructor
corolla.print();
Car junker("Junker", 350); // 2-param constructor
junker.print();
Compile and run your program and verify you see the car information printed like:
none @ 0 with MPG: 0
Enter the name of the car: Civic
Enter the price for a Civic: 19500
Enter the MPG for a Civic: 31
Civic @ 19500 with MPG: 31
Other cars for comparison:
Toyota Corolla @ 18500 with MPG: 30
Junker @ 350 with MPG: 10
User input is shown in italics for the example only, NOT in your program. If you have problems, ask a classmate or the instructor for help.
If you see output like the following for the junker, then you have a problem with shadowing.
@ 1.25384e+224 with MPG: 10
Correct the shadowing problem by changing the names of the parameters in the two-parameter constructor.
Write an accessor and mutator function for each member variable following the "standard" get
and set
naming protocol. For example, here are the prototypes for the name variable:
string getName();
void setName(string newName);
Write the same type of functions for member variables price
and mpg
. For more information see sections 9.3.4: Accessing Member Variables .
In main()
, call all the get
and set
functions at least one time. For example, the following calls the get and set functions for member variable mpg
:
cout << "Testing get and set functions\n";
Car tester("Calamity", 1000, 5);
cout << "The mpg of tester is: "
<< tester.getMpg() << endl;
tester.setMpg(25);
cout << "Tester's MPG is now: ";
tester.print();
You must add statements like this for member variables name
and price
as well.
Submit your exercise source code as part of assignment 9.
When finished please help those around you.
^ top
9.3.6: Summary
In this section we looked at more class features and pitfalls
Overloaded Constructors
Constructors are used to initialize all the member variables of a class
We can code a constructor with or without parameters
A constructor without parameters is known as a default constructor
We can use constructors with parameters to assign values to the member variables using the parameters
We can write a class with more than one constructor
If the class has more than one constructor, the constructor matching the argument list is used
For example, if our class has the following three constructors:
Product();
Product(string newName);
Product(string newName, double newPrice);
The following call the constructors in order
Product milk;
Product bread("Bread");
Product cheese("Cheddar", 6.75);
You must use care when calling a no-parameter constructor:
Product milk2(); // wrong (but compiles)
Product milk3; // right
Get and Set Functions
Shadowing
Local variables and parameters with same name as a class variable hide the class variable
We should not use the same name for a local variable and a class member variable
Check Yourself
What is the purpose of a constructor? (9.3.1 )
How many constructors can you define for each class? (9.3.2 )
When does a compiler automatically include a constructor? (9.3.2 )
How do you call a particular constructor when there are many of them? (9.3.3 )
How does the syntax for calling a default constructor differ from calling constructors that have parameters? Why? (9.3.3 )
What types of functions can access private member variables? (9.3.4 )
Since member variables should be declared private, how do you access them outside the member functions of the class? (9.3.4 )
Should you declare accessor and mutator functions for all class member variables? Why or why not? (9.3.4 )
What is meant by the term "shadowing"? (9.3.5 )
How do you avoid "shadowing"? (9.3.5 )
^ top
Wrap Up
Due Tomorrow:
A8-Multi-Function Programs (10/25/18)
Due Next:
A9-Getting Classy (11/1/18)
When class is over, please shut down your computer
You may complete unfinished exercises at the end of the class or at any time before the next class.
^ top
Last Updated:
Wed Oct 24 09:50:15 PDT 2018