11: Object-Oriented Programming

What We Will Cover


Continuations

Homework Questions?

Questions from last class?

11.1: Working with an Object

Objectives

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

  • Separate classes from applications
  • Pass objects to functions
  • Return objects from functions

11.1.1: Review of Classes and Objects

  • Previously we discussed how to code classes to create objects
  • Classes are coded to encapsulate and hide data
  • Data is hidden using the private access modifier:
  • private:
        string name;
        double price;
    
  • To access private data, you code public "set" and "get" functions
  • public:
        string getName() { return name; }
        double getPrice() { return price; }
        void setName(string newName);
        void setPrice(double newPrice);
    
  • In addition, you code other functions that perform the "behaviors" of the objects created from the classes
  • To create objects from the class, you specify the class name and a variable:
  • Product milk;
  • When the object is created, memory is allocated for the class variables
  • However, the memory is uninitialized
  • We can use the set functions to assign the memory values:
  • milk.setName("Milk");
    milk.setPrice(3.95);
    
  • However, this is cumbersome and provides no guarantee that the programmer using our class will completely initialize the class data
  • The solution is to code constructor functions
  • Product(string newName, double newPrice);
  • Constructors are called whenever an object is created from a class
  • Product::Product(string newName, double newPrice) {
        setName(newName);
        setPrice(newPrice);
    }
    
  • Now we know how to code classes and construct objects
  • In this section we look at some ways you can make use of an object

11.1.2: Separating Classes from the main() Function

  • When you work with classes and objects, you usually specify a class in one file and write code to use the class in another file
  • This creates a more modular set of classes and allows you to reuse classes in other programs
  • 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

  • In C++, each program can have only one main() function
  • Usually, the main() function is coded in a file separate from all the other classes and functions
  • Then any functions or classes needed by main are added using the #include preprocessor directive
  • To demonstrate, we remove the main() function from our Product class as shown below
  • Note that without a main() function we can no longer compile the code
  • Trying to compile causes a linker error because every program must have a main() function
  • ...undefined reference to `_WinMain@16'
    collect2: ld returned 1 exit status
    
  • We will show how to compile it in the next section

Class Product Without a main() Function

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

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

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

Product::Product(string newName) {
    setName(newName);
    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;
}

11.1.3: Including a Class in an Application

  • Now let us look at how to create an application by including the separate Product.cpp file
  • The following program is called productapp
  • It is a main() function that includes the Product class using the #include directive
  • #include "Product.cpp"
  • Later on we will look at more sophisticated uses of using separate files

Program productapp.cpp

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

11.1.4: Returning Objects from Functions

  • Objects can be returned from functions
  • We can make a simple function to demonstrate this technique
  • Product makeProduct() {
        string name;
        double price;
    
        cout << "Enter a product name: ";
        cin >> name;
        cout << "Enter the price for a "
             << name << ": ";
        cin >> price;
    
        Product newProd(name, price);
        return newProd;
    }
    
  • We revise our productapp.cpp file to add this function as shown below

Revised productapp.cpp

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;

#include "Product.cpp"

Product makeProduct();

// For testing class Product
int main() {
    char choice = 'Y';
    while ('Y' == choice || 'y' == choice) {
        Product prod = makeProduct();
        cout << "You entered:"
             << "\n   Name: " << prod.getName()
             << "\n   Price: " << prod.getPrice()
             << endl;

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

    return 0;
}

Product makeProduct() {
    string name;
    double price;

    cout << "Enter a product name: ";
    cin >> name;
    cout << "Enter the price for a "
         << name << ": ";
    cin >> price;

    Product newProd(name, price);
    return newProd;
}

11.1.5: Passing Objects to Functions

  • We can pass objects to functions parameters
  • We can pass objects by value or by reference
  • However, usually we pass objects by reference because it requires less work by the computer
  • As an example of passing objects to functions, we add a new function to our Product class definition
  • bool isEqual(Product& prod);
  • For the function definition we add:
  • bool Product::isEqual(Product& prod) {
        bool equal = false;
        if (name == prod.name && price == prod.price) {
            equal = true;
        }
        return equal;
    }
    
  • Note that there is only one function parameter and not two
    prodA.isEqual(prodB)
  • We are comparing the current Product object (prodA) against a second Product object (prodB)
  • We revise our productapp.cpp file to test this as shown below

Revised productapp.cpp Using the isEqual() Function

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

#include "Product.cpp"

Product makeProduct();

// For testing class Product
int main() {
    char choice = 'Y';

    cout << "Enter the first product\n";
    Product prodA = makeProduct();

    while ('Y' == choice || 'y' == choice) {
        cout << "\nEnter a product to check\n";
        Product prodB = makeProduct();

        if (prodA.isEqual(prodB)) {
            cout << "Products match!\n";
        } else {
            cout << "Products do NOT match!\n";
        }

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

    return 0;
}

Product makeProduct() {
    string name;
    double price;

    cout << "Enter a product name: ";
    cin >> name;
    cout << "Enter the price for a "
         << name << ": ";
    cin >> price;

    Product newProd(name, price);
    return newProd;
}

11.1.6: Summary

  • In this sections we looked at some techniques for working with an object
  • We started by placing the Product class definition into a file separate from the main() function
  • The reason was to make the class more modular and allow it to be used in other applications
  • Then we looked at specifying a class type as a return type of a function
  • Finally, we looked at specifying a function with an object parameter

Check Yourself

  1. Why should you code classes in files separate from a main() function?
  2. How do you add code from a separate file into the file that has a main() function?
  3. How do you code a function to return an object?
  4. How do you code a function with an object parameter?

Exercise 11.1

In this exercise we look at how to separate the class code from the main() function.

Specifications

  1. Use the following code and separate it into two files.
  2. In a file named myrectangle.cpp, save the class declaration and definition.
  3. In a file named rectangleapp.cpp, save the main() function
  4. Write a #include preprocessor directive to include the MyRectangle class in the rectangleapp.cpp file.
  5. Submit both files as the solution to this exercise.
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
#include <iostream>
using namespace std;

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

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

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

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

    return 0;
}

11.2: Working with Multiple Objects

Objectives

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

  • Code classes that use other classes
  • Code arrays of objects

11.2.1: About Multiple Objects

  • In OOP, only the simplest programs use a single object
  • More commonly, you have several objects working together in your program
  • Each object performs one specialized task
  • In this section we look at how use multiple objects in a program

Product Class

  • Before we start, lets recall 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
52
53
54
55
56
57
#include <iostream>
using namespace std;

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

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

Product::Product(string newName) {
    setName(newName);
    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;
}

11.2.2: Objects as Instance Variables

  • Different applications can use existing classes to create objects
  • For example, the following class uses a Product object in the class definition
  • private:
        Product product;
    
  • Note how the Product class is initialized in the constructor
  • ProductOrder::ProductOrder(string name, double price,
            int prodQuantity): prod(name, price) {
    
  • What else do you notice that is new about the following code?

Example Class with an Object 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
using namespace std;

#include "Product.cpp"

class ProductOrder {
public:
    ProductOrder();
    ProductOrder(string name, double price,
                 int prodQuantity);
    Product getProduct() { return prod; }
    double getQuantity() { return quantity; }
    void setProduct(Product& newProduct);
    void setQuantity(int newQuantity);
    double getTotal();
    void showData();
private:
    Product prod;
    int quantity;
};

ProductOrder::ProductOrder() {
    quantity = 0;
}

ProductOrder::ProductOrder(string name, double price,
        int prodQuantity): prod(name, price) {
    quantity = prodQuantity;
}

void ProductOrder::setProduct(Product& newProduct) {
    prod = newProduct;
}

void ProductOrder::setQuantity(int newQuantity) {
    quantity = newQuantity;
}

double ProductOrder::getTotal() {
    return quantity * prod.getPrice();
}

void ProductOrder::showData() {
    cout << "Name: " << prod.getName()
         << "\nPrice: "
         << prod.getPrice()
         << "\nQuantity: " << quantity
         << "\nTotal Amount: "
         << getTotal() << "\n";
}

  • Note that the getTotal() function does not simply return a value
  • Instead, it calculates the total by using variables of both the prod object and the ProductOrder class

11.2.3: Storing Objects Within Objects

  • When an object is created as part of another object, room for both objects are allocated in memory
  • This is shown in the following diagram
  • Both objects exist, but one object is nested within another

11.2.4: Another Example Application

  • productorderapp.cpp is another driver application
  • It has a main() function so we can compile and link the application

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

#include "ProductOrder.cpp"

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

        ProductOrder po(name, price, qty);
        cout << "\nYou entered:\n";
        po.showData();

        cout << "\nEnter another product order? ";
        cin >> choice;
    }

    return 0;
}

  • Note that we now have two applications sharing the same class: Product
    • productapp.cpp: from lesson 11.1.3
    • productorderapp.cpp: shown above
  • This is an example of code reuse

11.2.5: Arrays of Objects

  • Let us look at another way to use multiple objects
  • Any type can be made into an array, including class types
  • Product prods[10];
  • In the following, array elements are objects
  • You can call methods of the objects stored in each array element
  • Note that this is yet another application making use of the 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
52
53
#include <iostream>
#include "product.cpp"
using namespace std;

const int MAX_PRODS = 100;
const int START_PRODS = 3;

// Display all the products
void showProducts(Product prods[], int numProds);

int main() {
    // Create 3 Product objects
    Product milk("Milk", 3.95);
    Product bread("Bread", 1.09);
    Product cheese("Cheese", 4.59);

    // Preassign objects to an array
    Product store[MAX_PRODS] = { milk, bread, cheese };

    // Enter more products into the array
    int count = START_PRODS;
    char choice = 'Y';
    showProducts(store, count);
    cout << "Enter another product? ";
    cin >> choice;
    while (('Y' == choice || 'y' == choice)
            && count < MAX_PRODS) {
        string name;
        double price = 0.0;
        cout << "Enter a product name: ";
        cin >> name;
        cout << "Enter the price for a "
             << name << ": ";
        cin >> price;

        store[count].setName(name);
        store[count].setPrice(price);
        count++;

        showProducts(store, count);
        cout << "Enter another product? ";
        cin >> choice;
    }

    return 0;
}

void showProducts(Product prods[], int numProds) {
    cout << "\nAvailable products:\n";
    for (int num = 0; num < numProds; num++) {
        prods[num].show();
    }
}

Notes on the Code

  • Code that accesses each individual array element
  • Product prod = store[num];
    
  • Code that calls a function on each array element
  • cout << store[num].getPrice();
    

11.2.6: Summary

  • Object-oriented programs usually use more than one class
  • One way is for class types to be part of the data for other classes
  • class ProductOrder {
    // ... more code here
    private:
        Product product;
        int quantity;
    };
    
  • When an object is created as part of another object, room for both objects are allocated in memory
  • Since we write classes to be modular, different applications can use the same classes
  • We reviewed several applications in this section that used the Product class
  • One of the applications used an array of classes
  • Product milk("Milk", 3.95);
    Product bread("Bread", 1.09);
    Product cheese("Cheese", 4.59);
    
    Product store[] = { milk, bread, cheese };
    
  • This allowed us to use a loop to access each object
  • for (int num = 0; num < NUM_PRODS; num++) {
        Product prod = store[num];
        cout << prod.getName() << " @ ";
        cout << store[num].getPrice();
        cout  << endl;
    }
    
  • This is a useful technique for combining arrays and objects

Check Yourself

  1. How do you code an object as an instance variable of another class?
  2. How do you code an array of objects?

Exercise 11.2

In this exercise we explore the flow of control when one class is part of another class.

Specifications

  1. Copy the following 3 files into TextPad and set them up so you can view the line numbers
  2. Create a file named trace.txt
  3. In the trace.txt file, list the file name and number of each line for the following program in the order the lines are processed like this:
  4. ProductOrderApp: 7, 8, 9 ... more tracing here
    ProductOrder: 26, 27 ... more tracing here
    ... more files and tracing here
    

    Do not bother to list lines containing only a closing curly brace (}) of a function definition.

  5. Submit the trace.txt file as the solution to this exercise.

Wrap Up

    Reminders

    Due Next: A10: Getting Classy (5/3/07)
    Exercise 10 (5/3/07)
    Exercise 11 (5/10/07)

  • Also: Sampler Project
  • 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.

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

Last Updated: May 17 2007 @17:09:14