8: Coding Classes and Objects

What We Will Cover


Continuations

Midterm Questions

Homework Questions?

Questions from last class?

What type of stream must be used to send data from a program to a file?

  1. input stream
  2. output stream
  3. character stream
  4. binary stream

8.1: Introduction to Classes and Objects

Objectives

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

  • Describe what classes, objects, functions and instance variables are
  • Declare a class and use it to create an object
  • Call an object's function to perform a task

8.1.1: About Classes and Objects

  • Everywhere you look in the real world you see objects
    • People
    • Animals
    • Plants
    • Buildings
    • Cars
  • Humans, including programmers, think in terms of objects
  • Humans learn about objects by studying their attributes and behaviors
  • Attributes are things like: size, shape, color and weight
  • Behaviors are what an object does, like:
    • A person walks, runs, crawls, talks and sits
    • A plant grows and wilts
    • A car accelerates, brakes and turns
  • Object-oriented programming (OOP) grew out of using software to model complex systems in the real world
    • Spread of disease in humans, animals and plants
    • Design of buildings or other large objects
    • Design of cars
    • Ecosystem simulation
    • Network routing
    • Weather prediction
  • Object-oriented design (OOD) models software like the way people study objects in the real world
  • It takes advantage of relationships where objects of a certain class, like buildings, have similar attributes and behaviors
  • OOD provides a natural and intuitive way to view software design
    • Once you get used to it
  • OOD models objects by describing their attributes and behaviors
  • It also models communication between objects
  • Just as people send messages to each other, software objects send messages
  • For example, a house object may receive a message to open or close a door

8.1.2: Modeling Objects in Software

  • Let's use a simple analogy to help us understand classes and objects
  • Suppose you want to build your own home
  • You find the blueprints of a house that you like
  • These blueprints describe all the attributes of the house, like:
    • size
    • shape
    • location of rooms
  • Within this blueprint are the actions you can perform on your house, like:
    • Open doors in the front of the house
    • Turn on a furnace to heat the house
  • We can use this analogy to introduce some of the OOP concepts
  • The blueprint is like a class in OOP
  • We create a description of the object by writing a class
  • A class describes the attributes of an object using instance variables
  • With class House, we might have instance variables such as:
    • double length: the length of the house
    • double width: the width of the house
    • bool frontDoorOpen: whether or not the front door is open
  • Instance variables are said to hold the state of an object
  • A class also describes the behavior of an object using instance functions
  • For example, class House might have a function like:
    • void openFrontDoor(): set data values to show the door as open
  • However, a blueprint of a house is not a house
  • Before you can live in the house a construction crew must build it
  • The construction crew uses the blueprints to make the house
  • Similarly, you must create an object of a class before you can use an object
  • After an object is built, you send messages to an object
  • How we send messages to a real house is we open the door
  • To send messages to a software house, we call its instance functions

8.1.3: Declaring a Class with a Function

  • Let us continue our analogy by writing a class for a house
  • We will keep it simple since we only want a simple model
  • All classes start with a statement declaring the class
  • For our first house class, we include a function to open the front door

Class House

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

class House {
public:
    void openFrontDoor();
};

// Instance function definition
void House::openFrontDoor() {
    cout << "Opening front door\n";
}

// Using the House class
int main() {
    House myHouse;
    myHouse.openFrontDoor();
    House yourHouse;
    yourHouse.openFrontDoor();

    return 0;
}
  • The class declaration begins with:
  • class House {
  • Every class declaration includes the keyword class followed by its name
  • In addition, ever class's body is enclosed in a pair of curly braces
  • The keyword public is an access specifier or visibility modifier
  • This indicates that everything following is "available to the public"
  • More specifically, everything following can be accessed from outside the class

Instance Function Declaration (Prototype)

  • The function declaration is:
  • void openFrontDoor();
  • Because the function declaration comes after the keyword public, it is "available to the public"
  • The function declaration includes the return type, name and a semicolon
  • This is the same syntax we have used for functions declarations before
  • The only difference is that the function declaration is contained inside the curly braces of the class

Instance Function Definition (Body)

  • The definition of the function is outside the class:
  • void House::openFrontDoor() {
        cout << "Opening front door\n";
    }
    
  • This is like previous function definitions except for: House::
  • We need to use House:: to tell the compiler that the declaration for the function is inside the class House

8.1.4: Instantiating an Object and Calling a Function

  • Now we would like to use our House in an application
  • Every application must have one main() function
  • Note that our code has a main() function like other programs be have built so far
  • int main() {
        House myHouse;
        myHouse.openFrontDoor();
        House yourHouse;
        yourHouse.openFrontDoor();
    
        return 0;
    }
    
  • However, the main() function is not part of the class
  • You can tell that main() is not part of the class because it is:
    • Not inside the class House
    • Does not have House:: in front of the name

Instantiating an Object

  • To use a class, you usually start by creating an object of the class
    • Also known as creating an instance of the class
  • In C++ you can create an instance of a class by:
    1. Writing the class name
    2. Followed by a variable name to store the object
  • For example:
  • House myHouse;
    
  • The variable name is known as the object name

Calling an Instance Function (Sending a Message)

  • In our application, we want to call the openFrontDoor() function
  • To call a function, you use the object name, a dot (period), the function name and a set of parenthesis
  • myHouse.openFrontDoor();
  • When we call the function, we are sending a message to myHouse to "open the front door"
  • We need the object name in front of the function names to say which object we want to use
  • myHouse.openFrontDoor();
    yourHouse.openFrontDoor();
    
  • In the first function call, we are opening the front door of myHouse
  • In the second function call, we are opening the front door of yourHouse

8.1.5: Declaring Instance Variables

  • Classes usually have one or more functions that manipulate the attributes that belong to an object of the class
  • Instance variables store the attributes of an object
  • Each object maintains its own copy of these variables
  • To continue our analogy, we will update our House class with an instance variable

Class House with an Instance Variable

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
#include <iostream>
using namespace std;

class House {
public:
    void setColor(string newColor);
    string getColor();
private:
    string color;
};

// Instance function definitions
void House::setColor(string newColor) {
    color = newColor;
}

string House::getColor() {
    return color;
}

int main() {
    House myHouse;
    myHouse.setColor("Blue");
    cout << "The color of myHouse is: "
         << myHouse.getColor() << endl;

    return 0;
}

An Instance Variable

  • The instance variable is declared after the keyword private:
  • private:
        string color;
    
  • Instance variables are declared inside a class declaration but outside the bodies of the class's functions
  • The keyword private means that the instance variable is not accessible outside the class
  • Most instance variables are declared private
    • Declaring an instance variable as private is known as data hiding
    • We will discuss why this is done later

Instance Functions

  • To make use of an instance variable, we use an instance function that manipulates the variable
  • In our class, we have two such instance functions
  • Function setColor() will set or change the color of a House object
  • void House::setColor(string newColor) {
        color = newColor;
    }
    
  • Function getColor() will return the color of a House object
  • string House::getColor() {
        return color;
    }
    
  • How can we tell that these functions are part of class House?

Testing Class House

    int main() {
        House myHouse;
        myHouse.setColor("Blue");
        cout << "The color of myHouse is: "
             << myHouse.getColor() << endl;
    
        return 0;
    }
    
  • Our main() function instantiates a House object:
  • The myHouse.setColor() function is called to set the color to "Blue"
  • The myHouse.getColor() function is called to get the current color of myHouse

8.1.6: Summary

  • In object-oriented programming, objects are modeled after real-world objects
  • Object-oriented design (OOD) takes advantage of relationships where objects of a certain class, like houses, have similar attributes and behaviors
  • In object-oriented programming (OOP), we create a "blueprint" of an object by writing a class
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
#include <iostream>
using namespace std;

class House {
public:
    void setColor(string newColor);
    string getColor();
private:
    string color;
};

// Instance function definitions
void House::setColor(string newColor) {
    color = newColor;
}

string House::getColor() {
    return color;
}

int main() {
    House myHouse;
    myHouse.setColor("Blue");
    cout << "The color of myHouse is: "
         << myHouse.getColor() << endl;

    return 0;
}
  • Just like a blueprint is not a house, a class is not an object
  • Before we can use an object, we must create (instantiate) an object from the class
  • There are two steps to creating an object:
    1. Writing the class name
    2. Followed by a variable name to store the object
  • For example:
  • House myHouse;
  • One you create an object, you can "pass it a message" by calling its functions
  • myHouse.setColor("Blue");
  • Classes usually have functions that manipulate the attributes that belong to an object of the class
  • Instance variables store the attributes of an object
  • Each object maintains its own copy of these variables in the computer's memory
  • Instance variables are declared inside a class declaration but outside the bodies of the class's functions
  • Most instance variables are declared with the access modifier private
  • private:
        string color;
    
  • Since the private modifier prevents access outside an object of the class, you must use the instance functions of the class to access an instance variable
  • We will discuss why this is done in the next section

Check Yourself

  1. What is a class?
  2. What is an object?
  3. What is the difference between a class and an object?
  4. What is the syntax for declaring a class?
  5. How do you create an object from a class?
  6. How do you pass a message from one object to another?
  7. How do you call an object's functions?
  8. How does an object maintain state (remember its current settings)?

Exercise 8.1

In this exercise we trace the execution of a program using a class.

  1. Start a text file named exercise8.txt.
  2. Prepare the exercise header as described in the HowTo on submitting exercises
  3. Label this exercise: Exercise 8.1
  4. In exercise8.txt, list the line numbers of the following program in the order they are processed.
  5. Do not bother to list lines containing just a closing curly brace (}) of a function definition.
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
#include <iostream>
using namespace std;

class House {
public:
    void setColor(string newColor);
    string getColor();
private:
    string color;
};

// Instance function definitions
void House::setColor(string newColor) {
    color = newColor;
}

string House::getColor() {
    return color;
}

int main() {
    House myHouse;
    myHouse.setColor("Blue");
    cout << "The color of myHouse is: "
         << myHouse.getColor() << endl;

    return 0;
}

8.2: Coding Classes to Create Objects

Objectives

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

  • Describe the concept of encapsulation and data hiding
  • Design classes that create objects
  • Code instance variables, constructors, and instance functions

8.2.1: Encapsulation and Data Hiding

  • As programs become larger, you need to change the way you work on them
  • Large programs usually have teams of people who work on them
    • One or two software engineers may work on the user interface
    • Another two or three may work on the logic of the application and various features
    • Another may work on data storage and retrieval
  • When many programmers work together, you need to take special care to protect the data of the application
  • For instance, two or three people may work on code to retrieve data from a database, make some computation and then display if on a screen
  • Unless the programmers take care, they may accidentally store incorrect values in the variables
  • These incorrect values show up as "strange bugs" that creep into the program
  • Object-oriented programs provide two important ways to help protect and control program data:
    • Encapsulation
    • Data hiding

Encapsulation

    Encapsulation: inclusion of a number of items into a single unit

  • Objects allow you to group many variables together in a program
  • This allows you to process the values and move them around together in your program
  • If the groupings are logically related, then you can more easily keep track of what is happening with the data
  • For example, we can keep all the data about a car inside one object
  • In addition to data, objects allow you to add functions to the groupings of variables
  • The idea is to add functions that work on the group of data
  • Thus, functions like setting the speed or amount of fuel in a car are grouped into the class that describes a car

Data Hiding

    Data hiding: restricting a program from directly accessing the data stored in a class

  • If you want to prevent a program from setting wrong values in the variables of an object, you need to check it first
  • To accomplish this, you "hide" the data by preventing assignment to the variables outside the object
  • Instead, you write functions to set new values in the variables
  • In these functions, you check the data to ensure the values are valid
  • These functions for setting and retrieving data are known as an object's interface

8.2.2: Defining Classes

  • Let us look at how to define classes using encapsulation and data hiding
  • Basic Syntax
  • class className {
        permissionLabel1:
            member1;
        permissionLabel2:
            member2;
        ...
    };
    

For Example

  • The following is the code for a class named Product
  • Class declarations can contain three general sections:
    • Constructors
    • Instance functions
    • Instance variables
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
#include <iostream>
using namespace std;

class Product {
public:
    // Constructors
    Product();
    Product(string newName, double newPrice);
    // Instance functions
    string getName() { return name; }
    double getPrice() { return price; }
    void setName(string newName);
    void setPrice(double newPrice);
    void show();
private:
    // Instance variables
    string name;
    double price;
};

// no-parameter constructor
Product::Product() {
    name = "Unknown";
    price = 0.0;
}

Product::Product(string newName, double newPrice) {
    setName(newName);
    setPrice(newPrice);
}

void Product::setName(string newName) {
    if (newName.length() == 0) {
        name = "Unknown";
    } else {
        name = newName;
    }
}

void Product::setPrice(double newPrice) {
    if (newPrice > 0.0) {
        price = newPrice;
    } else {
        price = 0.0;
    }
}

void Product::show() {
    cout <<  name << " has a price of $"
         << price << endl;
}

// For testing
int main() {
    Product milk("Milk", 3.95);
    Product bread("Bread", 2.99);
    milk.show();
    bread.show();

    return 0;
}
  • Note that there are two sections to the code
  • The class is declared between the curly braces following the class name
  • Class member functions are defined after the class declaration
  • To show that the function belongs to the class, you use the class name and the scope resolution operator "::"
  • void Product::setName(string newName) {
        //...
    }
    

Private Members and Data Hiding

  • Note the keywords private and public
  • Referred to as permission labels, access specifiers or visibility modifiers
    • private: can only be accessed by member functions of this class
    • public: can be accessed by member functions of any class
  • Setting private accessibility for all data is a good design practice
  • Protects data by controlling access only through the public functions
  • Allows us to change how data may be stored at some future time
    • Without affecting code outside the class

Programming Style: Class Naming Conventions

  • Use nouns to name classes -- they represent objects
  • Start class names with a capital letter
  • Capital letter differentiates classes from functions and variables

8.2.3: Coding Instance Variables

  • We now look at each section in more detail
  • Instance variables store the attributes (data) of an object
  • Each object has its own copy of these variables
  • Syntax for declaring instance variables:
  • type variableName
  • For now, use the private access modifier for all instance variables
  • The type can be any primitive type or a class name
  • Instance variables work just like variables you have used previously
  • Only difference is they are declared inside the class and outside of any function body

Examples

    private:
        string name;
        double price;
    

8.2.4: Coding Instance Functions

  • Instance functions define the operations that can occur on an object
  • Performing these operations is sometimes referred to as passing messages
  • Thus, objects use instance functions to pass messages to each other
  • The syntax for declaring instance functions:
  • returnType functionName(parameter list);
    
  • For example:
  • public:
        string getName() { return name; }
        double getPrice() { return price; }
        void setName(string newName);
        void setPrice(double newPrice);
    
  • The syntax for defining functions declared in a class:
  • returnType ClassName::functionName(paramters) {
        // statements of the function
    }
    
  • For example:
  • void Product::setPrice(double newPrice) {
        if (newPrice > 0.0) {
            price = newPrice;
        } else {
            price = 0.0;
        }
    }
     
  • In general, you should declare most class functions public
  • However, if you want to prevent other classes from using a function, declare it private
  • The name of the function combined with the parameter list form its signature
  • You can have many functions with the same name in a class
    • However, each must have a different signature

Inline Functions

  • Note that some functions define the function body along with the declaration
  • These are known as in-line functions
  • For example:
  • string getName() { return name; }
    double getPrice() { return price; }
    
  • It is common practice to code such short function bodies in the class definition section

Function Naming Conventions

  • As mentioned before, use verbs for function names
    • Appropriate since they perform an action
  • Also start function names with a lower case letter
  • Not required, but is a convention that professional programmers follow

Set Functions

  • When variables are declared private, you may still need to modify them
  • Use public functions to allow modification of the data
  • Called set functions (a.k.a. mutator functions)
  • Use the name of the variable with the word set prepended
  • Such functions should verify the value is correct before setting it
  • For example:
  • void Product::setPrice(double newPrice) {
        if (newPrice > 0.0) {
            price = newPrice;
        } else {
            price = 0.0;
        }
    }
    

Get Functions

  • Also, you often need access to private variables
  • Use public functions to access the data
  • Called get functions (a.k.a. accessor functions)
  • Use the name of the variable with the word get prepended
  • For example:
  • string Product::getName() {
        return name;
    }
    
  • When get functions are short, you can code them as inline functions
  • For example, the same function coded inline inside the class:
  • public:
    string getName() { return name; }
    

8.2.5: Coding Constructors

  • Constructors are a special type of function coded for a class
  • Constructors are called whenever an object is created from a class
  • A constructor's primary purpose is to initialize the instance variables of the object
  • Constructor declarations (prototypes) are placed inside the class declaration
  • Constructor definitions are usually placed outside the class declaration
    • Unless they are short
    • In which case they are defined inline
  • Syntax for declaring constructors:
  • ClassName(parameterList);
    
  • Place constructors in the public section of the class declaration
    • Your program calls the constructor when creating new objects
  • Constructors must use the same name and capitalization as the class name
  • public:
        // Constructors
        Product();
        Product(string newName, double newPrice);
    
  • Constructors can have zero or more parameters, just like functions
  • You can have many constructors in a class, but each must have a different signature
  • The name of the constructor combined with the parameter list form its signature

Example: Constructor Definition with no Parameters

  • If you do not want to accept arguments for instance variables, code a constructor with no parameters:
  • Product::Product() {
        name = "Unknown";
        price = 0.0;
    }
    
  • Note that constructors with no parameters are called no-arg constructors

Example: Constructor Definition with two Parameters

  • If you want to accept arguments for all instance variables, code a constructor with parameters for each variable:
  • Product::Product(String newName, double newPrice) {
        setName(newName);
        setPrice(newPrice);
    }
    

Example: Constructor Definition with one Parameter

  • If you want to accept only some arguments, code a constructor appropriately:
  • Product::Product(String newName) {
        setName(newName);
        price = 0.0;
    }
    

Default Constructors

  • If the programmer does not define a constructor, then the compiler supplies an empty one like the following:
  • public:
        Product() {}
    
  • However, if the programmer defines any constructor, the compiler does not
  • You should always define your own no-arg constructor

8.2.6: Creating Objects From Classes

  • After defining a class, we can create objects
  • Syntax for creating an instance of a class:
  • ClassName objectName(argumentList);
    
  • You must call the constructor with the correct sequence and type of arguments
  • If the class has more than one constructor, the constructor matching the argument list is used

For Example

  • We can code a main function to create an instance of our class
  • When the new operator is used, memory space is allocated for the object variables
  • The call to the constructor function copies the argument values to the parameters
  • int main() {
        Product milk("Milk", 3.95);
        Product bread("Bread", 2.99);
    }
    
  • When the constructor is called, memory is allocated for the class variables
  • private:
        string name;
        double price;
    
  • Next, the constructor starts executing
  • You can trace the program flow through the code of the class:
  • Product::Product(string newName, double newPrice) {
        setName(newName);
        setPrice(newPrice);
    }
    
    void Product::setName(string newName) {
        if (newName.length() == 0) {
            name = "Unknown";
        } else {
            name = newName;
        }
    }
    
    void Product::setPrice(double newPrice) {
        if (newPrice > 0.0) {
            price = newPrice;
        } else {
            price = 0.0;
        }
    }
    
  • Functions setName() and setPrice() are called with the appropriate arguments
  • Function setName() assigns the instance variable name the parameter newName
  • Function setPrice() assigns the instance variable price the parameter value of newPrice
  • One object, an instance of the class, has now been created and initialized
  • You can create as many objects as you need for your program
  • Once created, your program can access each object using its public functions:
  •     milk.show();
        bread.show();
        cout << milk.getPrice() << endl;
    

8.2.7: Summary

  • OOP addresses the problem of data protection through encapsulation and data hiding
  • Encapsulation and data hiding allow you to change the inner workings of a class without affecting other classes.
  • Classes are like a template or blueprint for creating objects
  • Objects are constructed from these classes
  • When you define classes, you code three general sections:
    • Instance variables
    • Constructors
    • Instance functions
  • Instance variables store the data of an object
  • Constructors are called whenever an object is created from a class
  • Instance functions are the operations that can occur on the object
  • Access modifiers control access to variables, constructors and functions
    • private: can only be accessed by member functions of this class
    • public: can be accessed by member functions of any class
  • Use private for all variables and public for most functions
  • Use "set" functions to control setting of new values to private variables
  • Use "get" functions to return values of private variables
  • You create an instance of a class like the following:
  • Product milk("Milk", 3.95);
    

Check Yourself

  1. What is meant by the terms "encapsulation" and "data hiding"?
  2. What is the syntax for coding a class?
  3. How do you code instance variables?
  4. What are the differences between local variables and instance variables?
  5. How do you code a constructor for a class?
  6. When does a compiler automatically include a constructor?
  7. How many constructors can you define for each class definition?
  8. How do you code instance functions?
  9. What two instance functions are coded if you need to access an instance variable?

Exercise 8.2

In this exercise we write our first class.

Specifications

  1. Save the following starter code as Rectangle.cpp.
  2. Write suitable declarations for instance variables length and width.
  3. Code set and get functions for both of the variables following the recommended naming conventions.
    • Use the name of the variable with the word set prepended
    • Use the name of the variable with the word get prepended
  4. Write a constructor that sets the length and width variables.
  5. Write a show() function that displays some information about the object.
  6. Write a main function that instantiates two or more Rectangle objects and calls their show() functions.
  7. Submit your program code along with your other exercises for this lesson.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;

class Rectangle {
public:
    // Put constructor declarations here

    // Put function declaraions here

private:
    // Put instance variables here

};

// Put constructor definitions here

// Put function definitions here

// For testing
int main() {
    // place statements to instantiate objects here

    return 0;
}

8.3: Working with Classes and Objects

Objectives

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

  • Code no-arg constructor calls correctly
  • Write programs that use code from other files
  • Describe how to prevent "local shadowing"

8.3.1: More About Declaring an Object

  • Constructors are called in the object declaration
  • We can add the following two object declarations to our productapp.cpp program
  • Product defaultProduct;
    Product cheese("Cheddar", 6.75);
    
  • Notice the difference in how the two objects are initialized
  • First statement calls the no-arg constructor
  • Second statement calls a different constructor
  • It is an error to call the no-arg constructor like this:
  • Product defaultProduct2(); // wrong
  • However, the compiler will not catch the error!
  • It is legal syntax to declare a function like defaultProduct2() with no parameters
  • Trying to use defaultProduct2() will cause an error
  • defaultProduct2.getName();  // causes error

8.3.2: Including Files

  • When you work with classes and objects, you may use code in different files
  • In this section we look at how to use code from different files

Including Files

  • Recall the #include directive
  • #include <iostream>
  • It turns out that you can include your own files into another program file
  • Syntax:
  • #include "myfile.cpp"
  • For example:
  • #include "Product.cpp"

Programs and the main() Function

  • Each program, or application, can have only one main() function
  • To demonstrate, we remove the main() function from our Product class
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
#include <iostream>
using namespace std;

class Product {
public:
    // Constructors
    Product();
    Product(string newName, double newPrice);
    // Instance functions
    string getName() { return name; }
    double getPrice() { return price; }
    void setName(string newName);
    void setPrice(double newPrice);
    void show();
private:
    // Instance variables
    string name;
    double price;
};

// no-arg constructor
Product::Product() {
    name = "Unknown";
    price = 0.0;
}

Product::Product(string newName, double newPrice) {
    setName(newName);
    setPrice(newPrice);
}

void Product::setName(string newName) {
    if (newName.length() == 0) {
        name = "Unknown";
    } else {
        name = newName;
    }
}

void Product::setPrice(double newPrice) {
    if (newPrice > 0.0) {
        price = newPrice;
    } else {
        price = 0.0;
    }
}

void Product::show() {
    cout <<  name << " has a price of $"
         << price << endl;
}
  • Note that without a main() function we can no longer compile the code
  • Causes a linker error because every program must have a main() function
  • ...undefined reference to `_WinMain@16'
    collect2: ld returned 1 exit status
    

8.3.3: Example Application

  • Following is the productapp program
  • It includes the Product class using the #include directive
  • #include "Product.cpp"
  • Has a main function that starts an application
  • Creates Product objects as specified by the user
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
#include <iostream>
using namespace std;

#include "Product.cpp"

// For testing class Product
int main() {
    char choice = 'Y';
    string name;
    double price;
    while ('Y' == choice || 'y' == choice) {
        cout << "Enter a product name: ";
        cin >> name;
        cout << "Enter the price for a "
             << name << ": ";
        cin >> price;

        Product prod(name, price);
        cout << "You entered:"
             << "\n   Name: " << prod.getName()
             << "\n   Price: " << prod.getPrice()
             << endl;

        cout << "Enter another product? ";
        cin >> choice;
    }

    return 0;
}
  • Note the following code that instantiates (creates) the object
  • Product prod(name, price);
    
  • Also has code to use functions of a Product object
  • prod.getName()
    prod.getPrice()
    

8.3.4: Local Variables and Shadowing

  • Local variables with same name as a class variable hide the class variable
  • Any use of the variable's name will refer to the function variable
  • This is the source of many an elusive bug
  • Thus, you should not use the same name for a local variable and a class variable
  • Remember that a parameter is like a local variable but initialized in a special way
  • Thus you should use a different name for a parameter and a class variable
  • Which lines contain local shadowing in the following program?

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
#include <iostream>
using namespace std;

class MyRectangle {
public:
    MyRectangle(double length, double width);
    void showData();

private:
    double length;
    double width;

};

MyRectangle::MyRectangle(double length, double width) {
    length = length;
    width = width;
}

void MyRectangle::showData() {
    cout << "length: " << length
         << "\nwidth: " << width
         << endl;
}

// For testing
int main() {
    MyRectangle rec(3.0, 5.0);
    rec.showData();

    return 0;
}

8.3.5: Summary

  • When you work with classes and objects, you may use code in different files
  • To do this you need to use the #include directive
  • For example:
  • #include "myfile.cpp"
  • You must use care when calling a default constructor
    • Do NOT use parenthesis
    Product defaultProduct2(); // wrong
  • Local variables with same name as a class variable hide the class variable
    • Known as "shadowing"
  • You should not use the same name for a local variable and a class variable

Check Yourself

  1. How do "include" one file in another?
  2. How does the syntax for calling a no-parameter constructor differ from calling constructors that have parameters? Why?
  3. What is meant by the term "local shadowing"?

Exercise 8.3

The following program has errors that prevent its correct operation.

Specifications

  1. Save the following code as Shadowing.cpp.
  2. Fix the program so that it compiles and runs correctly.
  3. Submit your program along with your other exercises for this lesson.
  4. Label this exercise: Exercise 8.3
  5. Record the answers to these questions in exercise8.txt.
  6. Q1: What error messages are displayed by the compiler, if any, before you correct the errors?

    Q2: Which function contains the errors?

    Q3: What is the name of these type of errors?

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
#include <iostream>
using namespace std;

class MyRectangle {
public:
    MyRectangle(double length, double width);
    void showData();

private:
    double length;
    double width;

};

MyRectangle::MyRectangle(double length, double width) {
    length = length;
    width = width;
}

void MyRectangle::showData() {
    cout << "length: " << length
         << "\nwidth: " << width
         << endl;
}

// For testing
int main() {
    MyRectangle rec(3.0, 5.0);
    rec.showData();

    return 0;
}

Wrap Up

Home | WebCT | Announcements | Day Schedule | Eve Schedule
Course info | Help | FAQ's | HowTo's | Links

Last Updated: November 06 2005 @16:44:56