11. Objects and classes

Review Topics


General Information

Housekeeping

  • Make sure you follow along with this page linked in Canvas
  • Please keep your microphone off unless you are asking a question
  • Please turn on camera if you can (optional)
  • Use chat if you would like to comment or ask questions

Announcements

See Announcements link in Canvas for course information. Here are some other reminders:

  • Career fairs in April, see Career Services
  • Remember that PAs and the Individual Readiness Assurance Quiz are due before class on Tuesday.
  • Remember to post in the Pair programming partners discussion group if you need a partner
  • Remember that the exercises from this page are due Sunday at 9:00pm.
  • Remember that CAs, Labs, and Class Exercises may be completed up to two days late but with a 10%/day penalty.
  • Remember that some lab solutions are posted in Canvas Modules
  • Cabrillo College is allowing students to select the P/NP option by the grade deadline for the term
  • Free Fresh Market schedule: free fresh fruits and vegetables
  • Food & Housing Resources: free food, meals, temporary and permanent housing
  • COVID-19 Resources and Information: Includes loaner-laptop information
  • Campus WiFi Access
    • Aptos: parking lots K and L on this Cabrillo Aptos Map
    • Watsonville: parking lot at Watsonville Center

Homework Help

Learning from the Exam

Learner Outcomes

At the end of the lesson the student will be able to:

  • Know what was missed on the midterm
  • Decide on what to do to improve performance as needed

Post Exam Decisions

Exam Results

  • Congratulations to the 19 people who got an A and the 15 people who got a B!
  • People who prepared well did well

Compiler Errors

  • Code that does not compile contains an error
  • When given the tools to compile, your code must compile for a good score
  • How do you make a program with problems compile?

Learning from the Exam

  • Compare your code to the posted answers
  • Most everyone who fully completed the midterm study preparations passed the midterm with an A or B
  • For topics you found difficult, review the notes and homework, get help understanding, -- and then practice until perfect!
  • If you believe a question was graded incorrectly, please email me an explanation
  • Grading policies are listed in the Canvas Syllabus

Post Exam Survey

  • Please complete the following survey to help future students and the instructor. (5m)
  • Post Exam Survey
forked road

Making Decisions

  • Based on your progress in the course you need to make decisions
  • If you are doing well--keeping going!
  • If you are not doing well...you need to make decisions
  • Can you do better and are you willing to put in the effort?
  • Is it too late this semester or not?

Last Day to Withdraw Approaching

  • Last day to drop a full-term section with a grade of "W": 4/25/2021
  • See Admissions and Records: Dates and Deadlines
  • Grade calculation "what-if" available in Canvas Grades

Why Learn to Program?

  • Learning to program is hard
  • But learning to program will help you
  • The world is changing. Fast. You need new skills to keep up
  • So many jobs we take for granted today will be gone in 10 years. (see below)
  • Computers are used in every industry, making programming an important skill in any career
  • Almost half of all high-income jobs (> $57,000 a year) require programming skills when hiring (Burning Glass Technologies)

Image

Jobs of the Future

  • U.S. Bureau of Labor Statistics says software engineering jobs will grow 22% per year (Much faster than average)
  • Projected new jobs for computer occupations are much more than any other STEM field (Chart source BLS p.11)
  • Because the number of computers and computer technologies are growing so fast, few careers are as rewarding as computing
  • Computer science pays well with average starting salaries of $84,010. for new grads in 2019 vs. $53,889 for the average among all College Graduates (source: NACE Summer 2020)
  • And working as a software engineer is a lot of fun!

Why Just do Well When You can do Good Too

Jobs that won't exist in 2030 (via PricewaterhouseCoopers)

1. Uber drivers
2. Truck drivers
3. Cashiers
4. Librarians
5. Postal Couriers
6. Bank Tellers
7. Sales
8. Pilots
9. Sports Referees & Umpires
10. Textile Workers
11. Telemarketers
12. Retail Clerks
13. Waiters
14. Data Entry
11. Telemarketers
12. Fisherman
13. Waiters
14. Data Entry
15. Tax Preparers
16. Insurance Underwriters
17. Tax Collectors
18. Cargo & Freight Agents
19. Legal Secretaries
20. Accountants
21. Radio Analysts
22. Credit Analysts
23. Tax Preparers
24. Tellers
25. Lumberjacks
26. Etchers & Engravers
27. Manicurists
28. Loan officers
29. Farm Labor
30. Dental Laboratory Technicians
31. Pesticide Handlers
32. Fisherman
33. Real Estate Brokers
34. Restaurant Hosts & Hostesses
35. Receptionists
36. Gaming Dealers
37. Ushers / Ticket Takers
38. Bill & Account Collectors
39. Nuclear Power Reactor Operators
40. Electrical and Electronic Equipment Assemblers
41. Landscaping and Groundskeeping Workers
42. Auditors
43. Waiters & Waitresses
44. Budget Analysts
45. Bicycle Repairers
46. Tire Builders
47. Jewelers and Precious Stone and Metal Workers
48. Cement Masons
49. Welders
50. Agricultural Inspectors
51. Paralegals and Legal Assistants
52. Pharmacy Technicians
53. Insurance Sales Agents
... and many more

More Information

11.1: Readiness Assessment Quizzes

  • Reading and participation activities are due before the first class meeting of the week
  • Quizzes assess the comprehension of the reading and participation activities

Quiz Part 1: Individual Readiness Assessment

  • Complete this quiz solo to assess your reading comprehension and readiness
  • Must take this quiz before the first class meeting of the week to ensure you are ready for the team quiz
  • Cannot take the quiz late
  • Quiz is open book and notes but timed
  • Highest score is counted so take the quiz multiple times

Quiz Part 2: Team Readiness Assessment (20m)

  • Must attend the class meeting to take this quiz
  • Login to Canvas and enter the access code
  • Will move to breakout rooms with your team
  • Make sure you have the access code for the exam
  • Openly discuss what you believe to be the best answers for the questions
  • Decide how to agree on the answers
    • Strive to reach a consensus on quiz answers
    • If no consensus, work it out as you and others in your group see fit
  • Turn in the quiz as a group
  • Each group member will receive the same score
  • Return to the main meeting room when finished

Quiz Appeals

  • After completing the team quiz, team members may appeal an answer
  • Appeals can be based on two criteria:
    1. Question is factually wrong

      Appeal must included citations to sources of information that document or support an alternative answer. Team may access reference materials during the appeal.

    2. Question is confusing based on it's wording

      Appeal must include an appropriate rewrite of questions or answers that you interpret as ambiguous or confusing.

  • Work with teammates to develop and write any appeals
  • Team has up to 24 hours after the quiz to email appeal to instructor
  • If appeal is granted, only the teams that submitted appeal gets credit

Image of a car with hood up to show parts

11.2: Defining a Class for an Object

The physical world is made up of objects--things like chairs, computers and cars. These objects are collections of items (parts) arranged in a certain way. We are use to mentally organizing our world into objects that are collections of more basic parts.

We know how to code basic items such as variables and 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 and variables. To solve this problem, computer scientists developed object-oriented programming (OOP).

Image of several cars in a row

In C++, we do not design a single object. Instead we design a class for creating one or more objects. From the class we are able to construct objects as we will see in the following sections.

11.2.1: Reviewing Class Definitions

  • Let us review 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 member variables to hold the object's data
  • After the class declaration we implement the member functions by writing the statements for the body of the functions
  • We will discuss implementation of the member functions in the next section

Class Declaration Syntax

  • The general syntax for declaring a class is:
    class ClassName {
        public:
        function declarations
    
        private:
        member variables
    };
    
  • Where:
    • ClassName: the name you make up for the class
    • function declarations: function prototypes for member functions
    • member variables: definitions of data members
  • Notice that the closing brace of the class is followed by a semicolon (};)
  • Usually programmers declare public: before private:

Example Class Definition

  • The following is an example class declaration: Replit
    class Product {
        public:
        void read();
        void print() const;
    
        private:
        string name;
        double price;
    };
    
  • The class declaration describes the programming interface for using the class
  • An interface describes how other parts of the program can interact with objects of our class
  • The interface consists of all the public members we define in a class
  • Members declared private are restricted and not part of the interface
  • For example, the above interface declares public member functions:
    • read(): read data from the console and store it in the object
    • print(): print the information about a product
  • The member variables are declared inside the class
  • However, all the member variables are "hidden" with the keyword private

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 Defining a Class

#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;
}

Camel Case

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 animal in the picture? (answer)

Exercise 11.2: Coding Class Definitions (5m)

In this exercise we define a class.

For this exercise we break into teams. Within the team, work with each other to develop a solution.

Specifications

  1. Start Replit and copy the following code into the code editor.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    

    We will call this code file car.cpp and add to it in the next 3 exercises.

  2. Declare a class named Car, and then compile your code to check for syntax errors.

    Remember the semicolon after the closing curly brace.

  3. Declare private member variables for a name, price and mpg (miles per gallon) with the appropriate data types.
  4. Declare two public prototypes for functions named read() and print() with void return types and no parameters.
  5. Compile and run the modified program to make sure you made the changes correctly.

    The program should compile without error or warning. When you run, nothing should happen yet.

  6. Save your source code file as we will be adding to it in the next Exercise.

When finished developing your code click hereClick to show answer to verify. Code need not look exactly the same. After you have completed your own program, reviewing another is often helpful in learning how to improve your programming skills.

11.3: Data Members and Objects

Variables declared inside a class are know as member variables, or more generally as data members. These variables define the memory allocated whenever an object is created.

11.3.1: Reviewing Data Members and Objects

  • An object stores its data in data members
  • Data members are the variables declared inside a class
  • Recall our example class declaration:
    class Product {
        public:
        void read();
        void print() const;
    
        private:
        string name;
        double price;
    };
    
  • The two member variables are name and price

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

Example Code

#include <iostream>
using namespace std;

class Product
{
    public:
    void read();
    void print() const;

    private:
    string name;
    double price;
};

// For testing
int main()
{
    Product milk;
    Product bread = Product();

    return 0;
}

Exercise 11.3: Coding Data Members and Objects (2m)

In this exercise we code an object for our class.

For this exercise, since it is short and easy, we will stay together as a class.

Specifications

  1. Continue with your source code from the last Exercise.
  2. In the main() function, define a Car object (Car class variable) like:
    int main() {
        Car tesla;
    
        return 0;
    }
    
  3. Compile and run the modified program to make sure you made the changes correctly.

    The program should compile without error or warning. When you run, nothing should happen yet.

  4. Save your source code file as we will be adding to it in the next Exercise.
  5. Think about this question: What does defining and compiling a Car variable tell us about class and objects?

When finished developing your code click hereClick to show answer to verify. Code need not look exactly the same. After you have completed your own program, reviewing another is often helpful in learning how to improve your programming skills.

11.4: Member Functions

Functions declared inside a class are known as member functions.

11.4.1: Reviewing Member Functions

  • To define behaviors for a class, we must implement member functions
  • We declare (prototype) member functions inside the class like:
    class Product {
        public:
        void read();
        void print() const;
    //... other code omitted
    };
    
  • Each member function prototype declared in the class interface must be implemented (defined)

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)

11.4.2: Mutator and Accessor Functions

Member functions are grouped into two broad types: mutators and accessors.

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:

    name = "none"
    price = 0

  • 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

  • Another type of function is the accessor function
  • An accessor function queries the object for some information without changing it
  • As an example of an accessor function, we define print() as follows:
    void Product::print() const {
        cout << name << " @ " << price << endl;
    }
    
  • The print() function displays information about a product without changing the value of any member variable
  • Because the function does not change any variable, we add the keyword const after the parenthesis
  • Whenever we design an accessor function, we should add the keyword const after the parenthesis
  • The const keyword tells the compiler to make sure that the function does not change the value of a member variable
  • Do NOT put const before the return type as that only affects the returned value

Dot Notation

  • Notice that when we access a member of an object we use "dot" notation
  • Recall that we used dot notation with strings like:
    string str = "Hello";
    cout << str.length() << endl;
    cout << str.substr(0, 4) << endl;
    
  • When constructing our own objects, we use dot notation as well
  • The dot separates the object name from the member name

Example Class Code with Member Functions

#include <iostream>
using namespace std;

class Product
{
    public:
    void read();
    void print() const;

    private:
    string name;
    double price;
};

void Product::read() {
    cout << "Enter a product name: ";
    cin >> ws;
    getline(cin, name);
    cout << "Enter the price for a " << name << ": ";
    cin >> price;
    cout << "You entered: ";
    print();
}

void Product::print() const {
    cout << name << " @ " << price << endl;
}

// For testing
int main()
{
    Product milk;
    milk.read();
    cout << "Printing in main(): ";
    milk.print();

    return 0;
}

Member Functions Calling Member Functions

  • When a member function calls another on the same object, we do not use dot notation
  • Instead we simply use the name of the function
  • As an example, suppose at the end of read() we decided to call print()
  • We would call print() so the user can confirm what data was entered
  • For example, we could implement the added code like this:
    void Product::read() {
        cout << "Enter the name of the product: ";
        cin >> ws;
        getline(cin, name);
        cout << "Enter the price for a " << name << ": ";
        cin >> price;
        cout << "You entered: ";
        print();
    }
    
  • Notice that we did not use dot notation to call print()
  • We only need dot notation when calling a member function from a non-member function like main()

11.4.3: Get and Set Functions

The simplest accessor and Mutator functions are the get- and set- functions.

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);
    
  • Thus a set function allws us to assign a value to a member variable

Get Functions

  • We often need to access the value of private variable from outside the class
  • For this we use public functions to get the value of private data
  • We refer to these functions as 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;
    

Exercise 11.4: Coding Member Functions (10m)

In this exercise we code member functions.

For this exercise we break into teams. Within the team, work with each other to develop a solution. When the team has finished, choose one member to show your solution to the class by sharing your screen. The instructor will ask one team to share their solution.

Specifications

  1. Continue with your source code from the last Exercise in Replit.
  2. After the class declaration, add the implementation (definition) 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.

  3. 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.

  4. Change the main() function to call the member functions like:
    int main() {
        Car tesla;
        tesla.read();
        tesla.print();
    
        return 0;
    }
    
  5. Compile your code to make sure it has correct syntax. Run the code and verify you see input and output like the following:
    Enter the name of the car: Tesla 3
    Enter the price for a Tesla 3: 35000
    Enter the MPG for a Tesla 3: 134
    Tesla 3 @ 35000 with MPG 134
    

    User input is shown in aqua italics for the example only, NOT your program.

  6. Once satisfied with your code, copy it into a text editor, save the file as "car.cpp", and submit the file to Canvas with the rest of the exercise files for the week.

When finished developing your code click hereClick to show answer to verify. Code need not look exactly the same. After you have completed your own program, reviewing another is often helpful in learning how to improve your programming skills.

11.5: Constructors

C++ does not assign a default value to a variable when declared. However, good practice is to initialize all variables when declared. We use a constructor to ensure an object's variables are initialized when the object gets constructed.

11.5.1: Reviewing Constructors

  • A constructor is a member function that initializes the data members of an object
  • The constructor is automatically called whenever an object is created
  • We add a constructor so we can ensure that all data members are properly set before other member functions act of an object
  • To understand the importance of the constructor consider the following code to test our Product class (Replit):
    #include <iostream>
    using namespace std;
    
    class Product {
        public:
        void read();
        void print() const;
    
        private:
        string name;
        double price;
    };
    
    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;
    }
    
    int main() {
        Product milk; // construct object milk
        milk.print(); // call print() function
    
        return 0;
    }
    
  • When we run the code, we see something like the following printed:
     @ 6.95315e-310
    
  • The problem is cause by uninitialized member variables
  • One solution to uninitialized member variables is to code a constructor

11.5.2: Adding a Constructor

  • We add a constructor function to our interface as shown in bold:
    class Product {
        public:
        Product();
        void read();
        void print() const;
    
        private:
        string name;
        double price;
    };
    
  • Constructors are a special type of function and thus are coded like a function
  • However, there are some syntax differences:
    • Constructors always have the same name as the class
    • Constructors do not have a return type, not even void
  • Continuing our example, we implement our Product constructor like this:
    Product::Product() {
        name = "none";
        price = 0.0;
    }
    
  • Now when re run our code, notice that the constructor does its job of initializing the class variables
  • Most of the time we initialize default values to zero
  • However, as we can see, we can choose to use other appropriate values as well
  • The following program has an added constructor

Example Class with a Constructor

#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;
}

11.5.3: In-class Member Initializers

  • Starting with C++-11, we can initialize values in the class
  • Thus we could assign initial values Like:
    private:
        string name = "none";
        double price = 0;
    
  • Thus in-class member initialization saves us some typing
  • However, there are still good uses for constructors as we will see the next section

Exercise 11.5: Coding Constructors (10m)

In this exercise we explore the use of constructors.

For this exercise we break into teams. Within the team, work with each other to develop a solution. When the team has finished, choose one member to show your solution to the class by sharing your screen. The instructor will ask one team to share their solution.

Specifications

  1. Continue with your source code from the last Exercise in Replit.

    If you did not keep the exercise, click here for starter code.

  2. 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;
    }
  3. 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: Tesla 3
    Enter the price for a Tesla 3: 35000
    Enter the MPG for a Tesla 3: 134
    Tesla @ 35000 with MPG 134
    

    User input is shown in aqua 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? Click to show answer

  4. 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;
    };
    
  5. After the class declaration,, add the following constructor definition.
    Car::Car() {
        name = "none";
        price = 0;
        mpg = 0;
    }
    
  6. 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: Tesla 3
    Enter the price for a Tesla 3: 35000
    Enter the MPG for a Tesla 3: 134
    Tesla 3 @ 35000 with MPG 134
    

    User input is shown in aqua 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.

  7. Once satisfied with your code, copy your code into a text editor, save the file as "ctor.cpp", and submit the file to Canvas with the rest of the exercise files for the week.

When finished developing your code click hereClick to show answer to verify. Code need not look exactly the same. After you have completed your own program, reviewing another is often helpful in learning how to improve your programming skills.

11.6: Constructor Overloading

We often find it convenient to have more than one constructor for a class.

11.6.1: Reviewing Constructor Overloading

  • Programmers often want to provide different initialization values when creating a new object
  • So far, we have been assigning default values in a default constructor
  • However, sometimes we want to create objects and assign them initial values that are not default
  • To accomplish this, we write a constructor with parameters
  • As an example, we may add the following constructor prototype to the interface of our Product class:
    Product(string newName, double newPrice);
    
  • We then define our constructor like this:
    Product::Product(string newName, double newPrice) {
        name = newName;
        price = newPrice;
    }
    
  • Notice that the member variable gets the value of the parameter variable
  • This is a common technique for assigning non-default values to member variables

Multiple Constructors

  • We may write a class with more than one constructor
  • All constructors have the same name as the class, but have different parameter lists
  • For example, we could define three different constructors in our Product interface:
        public:
        // Constructors
        Product();
        Product(string newName);
        Product(string newName, double newPrice);
    
  • The technique of defining multiple constructors is known as constructor overloading
  • Having multiple constructors allows us to create an object in different ways
  • By allowing different ways of creating an object, we make our classes more flexible and easier to reuse

Example: Default Constructor (No Parameters)

  • Constructors called with no parameters are known as default constructors
  • Calling a default constructor assigns default values to the member variables
    Product::Product() {
        name = "Unknown";
        price = 0.0;
    }
    

Example: Constructor Definition with one Parameter

  • If you want to accept only some arguments, code a constructor appropriately:
    Product::Product(string newName) {
        name = newName;
        price = 0.0;
    }
    
  • In the above, one member variable gets a default value and the other gets a value from the parameter

Example: Constructor Definition with two Parameters

  • If you want to accept arguments for all member variables, code a constructor with parameters for each variable:
    Product::Product(string newName, double newPrice) {
        name = newName;
        price = newPrice;
    }
    

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

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, order and data types of the parameters
  • 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 or the parameters in the correct order
  • We may define overloaded regular functions as well as constructors

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(); // does not construct an object
    
  • However, the compiler will not catch the error!
  • It is legal syntax to declare a function like milk2() with no parameters
    Product milk2(); // a function prototype
    
  • Thus, we will not see the error until we 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:
    Product milk = Product();
    

Exercise 11.6: Coding Overloaded Constructors (10m)

In this exercise we add more constructors to our class.

For this exercise we break into teams. Within the team, work with each other to develop a solution. When the team has finished, choose one member to show your solution to the class by sharing your screen. The instructor will ask one team to share their solution.

Specifications

  1. Continue with your source code from the last Exercise in Replit.
  2. Add a constructor declaration with three parameters to the class specification like the following:
    Car(string newName, double newPrice, double newMpg);
    
  3. After the class declaration, add a constructor definition (implementation) for the above constructor.
    Car::Car(string newName, double newPrice, double newMpg) {
        name = newName;
        price = newPrice;
        mpg = newMpg;
    }
    
  4. 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", 25000, 34);
    corolla.print();
    
  5. 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: Tesla 3
    Enter the price for a Tesla 3: 35000
    Enter the MPG for a Tesla 3: 134
    Tesla 3 @ 35000 with MPG 134
    Other cars for comparison:
    Toyota Corolla @ 25000 with MPG 34
    

    User input is shown in aqua italics for the example only, NOT in your program. If you have problems, ask a classmate or the instructor for help.

  6. Identify which constructor is called for each object and add a comment in your source code where the object is created.
  7. Once satisfied with your code, copy your code into a text editor, save the file as "multictor.cpp", and submit the file to Canvas with the rest of the exercise files for the week.

When finished developing your code click hereClick to show answer to verify. Code need not look exactly the same. After you have completed your own program, reviewing another is often helpful in learning how to improve your programming skills.

11.7: Vectors of Objects

List of objects are usually more convenient than managing parallel vectors.

11.7.1: Reviewing Vectors of Objects

  • Sometimes we need to keep track of multiple attributes about a list of items
  • A powerful way to accomplish this task is with vectors and classes
  • We keep the attributes organized by constructing objects from a class
  • As an example, look at the following vector of Product objects

Example Vector of Objects

#include <iostream>
#include <vector>
using namespace std;

class Product {
public:
    Product();
    Product(string newName, double newPrice);
    void print() const;
private:
    string name;
    double price;
};

Product::Product() {
    name = "Unknown";
    price = 0.0;
}

Product::Product(string newName, double newPrice) {
    name = newName;
    price = newPrice;
}

void Product::print() const {
    cout <<  name << " @ " << price << endl;
}

int main() {
    const int SIZE = 3;
    vector<Product> list(SIZE);
    list.at(0) = Product("Milk", 3.95);
    list.at(1) = Product("Bread", 2.99);
    list.at(2) = Product("Cheese", 3.95);

    cout << "Products in my store:\n";
    for (unsigned i = 0; i < list.size(); i++) {
        list.at(i).print();
    }

    return 0;
}

11.7.2: Adding Items to a Vector of Objects

In this section we look at a simple algorithm for adding an object to a vector.

  • To add items to a vector of objects we:
    1. First construct a temporary object like:
      Product temp;
    2. Next, read data into the temporary object such as by using a read() function like:
      temp.read();
    3. Finally, add the temporary object to the vector like:
      list.push_back(temp);
  • Putting all this together in a function we have:
    void addProduct(vector<Product>& store) { // function definition
        cout << "\nAdding a new product:\n";
        Product prod;               // construct an object
        prod.read();                // call member function read()
        store.push_back(prod);      // copy object onto vector
    }
    
  • The following example shows a complete program adding products to a vector of objects
  • Notice that main() contains a while-loop
  • By adding if-statements inside the loop, we make a simple menu system

Example Vector of Objects

#include <iostream>
#include <vector>
using namespace std;

class Product {
public:
    Product();
    Product(string newName, double newPrice);
    void read();
    void print() const;
private:
    string name;
    double price;
};

Product::Product() {
    name = "Unknown";
    price = 0.0;
}

Product::Product(string newName, double newPrice) {
    name = newName;
    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;
}

void addProduct(vector<Product>& store); // function prototype

void listProducts(vector<Product>& store); // function prototype

int main() {
    const int SIZE = 3;
    vector<Product> myStore(SIZE);  // vector of Product objects
    myStore.at(0) = Product("Milk", 3.95); // add objects to vector
    myStore.at(1) = Product("Bread", 2.99);
    myStore.at(2) = Product("Cheese", 3.95);
    int choice = 1;
    while (choice != 0) {
        cout << "\n0. Exit program\n"
             << "1. Report inventory\n"
             << "2. Add a new product\n"
             << "Choice (0-2): ";
        cin >> choice;
        if (choice == 1) {
            listProducts(myStore);    // call non-member function
        } else if (choice == 2) {
            addProduct(myStore);      // call non-member function
        } else if (choice != 0) {
            cout << "\nInvalid choice!\n";
        }
    }
    cout << "\nGoodbye!\n";
    return 0;
}

void addProduct(vector<Product>& store) { // function definition
    cout << "\nAdding a new product:\n";
    Product prod;               // construct an object
    prod.read();                // call member function read()
    store.push_back(prod);      // copy object onto vector
}

void listProducts(vector<Product>& store) {
    cout << "\nListing products:\n";
    for (unsigned num = 0; num < store.size(); num++) {
        cout << (num + 1) << " ";
        store.at(num).print();     // call member function print()
    }
}

Member vs. Non-member Functions

  • The above example has two member functions (besides the constructors):
    • void read();
    • void print() const;
  • In addition, the example has two non-member functions:
    void addProduct(vector<Product>& store);
    void listProducts(vector<Product>& store);
    
  • Notice the difference in the way the functions are called in the main() function
  • To call a member function we need an object of the class, like:
    Product temp;
    temp.read();
    
  • To call a non-member function, we do NOT need an object of a class:
    listProducts(list);
    
  • Also note that member functions typically have fewer parameters than non-member functions
  • The reason is that member functions work with the data contained in the object
  • In the following exercise we will work with both member and non-member functions

Exercise 11.7: Coding Vectors of Objects (18m)

In this exercise we explore how to add items to and list items of a vector of objects.

For this exercise we break into teams. Within the team, work with each other to develop a solution. When the team has finished, choose one member to show your solution to the class by sharing your screen. The instructor will ask one team to share their solution.

Specifications

  1. Start Replit and copy the following code into the code editor.
    #include <iostream>
    #include <vector>
    using namespace std;
    
    class Car {
        public:
        Car();
        Car(string newName, double newPrice, double newMpg);
        void read();
        void print() const;
    
        private:
        string name;
        double price;
        double mpg;
    };
    
    Car::Car() {
        name = "none";
        price = 0.0;
        mpg = 0.0;
    }
    
    Car::Car(string newName, double newPrice, double newMpg) {
        name = newName;
        price = newPrice;
        mpg = newMpg;
    }
    
    void Car::read() {
        cout << "Enter the name of the car: ";
        cin >> ws;
        getline(cin, name);
        cout << "Enter the price for a " << name << ": ";
        cin >> price;
        cout << "Enter the MPG for a " << name << ": ";
        cin >> mpg;
    }
    
    void Car::print() const {
        cout << name << " @ " << price << " with MPG " << mpg << endl;
    }
    
    int main() {
        Car myCar("Tesla", 35000, 134);
        myCar.print();
    
        return 0;
    }
    
  2. In main() after constructing the myCar object, construct a vector of Car objects named list with a size of one (1). Add the myCar object to list at element zero (0) and then print element zero. When finished main() should look like the following:
    int main() {
        Car myCar("Tesla", 35000, 134);
        vector<Car> list(1);
        list.at(0) = myCar;
        list.at(0).print();
    
        return 0;
    }
    

    Continue to compile and run after each step to test your code.

  3. Above the main() function, add the following function definition:
    void listCars(vector<Car>& list) {
        cout << "\nListing cars:\n";
        for (unsigned num = 0; num < list.size(); num++) {
            cout << (num + 1) << " ";
            list.at(num).print(); // call print() in Car
        }
    }
    
  4. In the main() function, call the listCars() function, replacing the call to print(). When finished main() should look like the following:
    int main() {
        Car myCar("Tesla", 35000, 134);
        vector<Car> list(1);
        list.at(0) = myCar;
        listCars(list);
    
        return 0;
    }
    

    Note that the listCars() function is calling the print() member function of Car.

  5. Above the main() function, add the following function definition:
    void addCar(vector<Car>& list) { // function definition
        cout << "\nAdding a new car:\n";
        Car aCar;               // construct an object
        aCar.read();            // call member function read()
        list.push_back(aCar);   // copy object onto vector
    }
    
  6. In the main() function, call the addCar() function and then call listCars() again. When finished main() should look like the following:
    int main() {
        Car myCar("Tesla", 35000, 134);
        vector<Car> list(1);
        list.at(0) = myCar;
        addCar(list);
        listCars(list);
    
        return 0;
    }
    

    Note that the addCar() function is calling the read() member function of Car.

  7. Compile and run your modified program to make sure you made the changes correctly. When running the program, the output should look like:
    Listing cars:
    1 Tesla @ 35000 with MPG 134
    
    Adding a new car:
    Enter the name of the car: Toyota Corolla
    Enter the price for a Toyota Corolla: 25000
    Enter the MPG for a Toyota Corolla: 34
    
    Listing cars:
    1 Tesla @ 35000 with MPG 134
    2 Toyota Corolla @ 25000 with MPG 34
    

    In the above example run, the user entered the values shown in aqua italics (for emphasis) in a terminal window to produce the output. Your program does NOT print the characters in aqua italics, nor does the user input appear in aqua italics.

  8. Now we want to create a short menu to call our functions. Replace the following sequence of three function calls in main()
    listCars(list);
    addCar(list);
    listCars(list);
    
    with the following code:
    int choice = 1;
    while (choice != 0) {
        cout << "\n0. Exit program\n"
             << "1. Report inventory\n"
             << "2. Add a new car\n"
             << "Choice (0-2): ";
        cin >> choice;
        if (choice == 1) {
            listCars(list);
        } else if (choice == 2) {
            addCar(list);
        } else if (choice != 0) {
            cout << "\nInvalid choice!\n";
        }
    }
    cout << "\nGoodbye!\n";
    
  9. Compile and run your modified program to make sure you made the changes correctly. When running the program, the menu output should look like:
    0. Exit program
    1. Report inventory
    2. Add a new car
    Choice (0-2):
    

    Also, you should be able to add and list products as often as you like.

  10. Once satisfied with your code, copy your code into a text editor, save the file as "carlist.cpp", and submit the file to Canvas with the rest of the exercise files for the week.

When finished developing your code click hereClick to show answer to verify. Code need not look exactly the same. After you have completed your own program, reviewing another is often helpful in learning how to improve your programming skills.

 

Last Updated: May 10 2021 @22:58:53