CS32, Fall 2012

Lab06:
Overloading operators in C++


Goals for this lab

By the time you have completed this lab and its homework, you should

Step by Step Instructions

Step 0: Get set up, including copying files to your lab directory

Partner up (and remember to switch roles after awhile). If your regular partner is more than 5 minutes late, ask the TA to pair you with someone else for this week. This lab's first pilot should log in. You will (both) work in this account for the rest of the lab.

Create a ~/cs32/lab06 directory, make it your current directory, and get copies of five files from the cs32 class account:

mkdir ~/cs32/lab06
cd ~/cs32/lab06
cp ~cs32/labs/lab06/* .

Step 1: Start building a Vec3 class

You are provided with a simple Makefile, main.cpp, and incomplete versions of vec.h and vec.cpp. There is also a file called main2.cpp to be used in the "After lab-work" section and the homework.

In this lab, you will need to add all the functionality that main.cpp expects from the Vec3 class. This requires both declaring new functions in vec.h and writing the corresponding implementation in vec.cpp. After making each class enhancement, you will uncomment lines in main.cpp to test it. The optional lab and the homework tasks follow the same procedures.

Right now: use an editor to type your name(s) and today's date in the comments at the top of two of these files: both vec.h and vec.cpp.

Study what's done already

The class already has a no-argument constructor, a constructor that takes three double values, and a copy constructor - all of which are implemented in vec.cpp too. Do not change the way they are defined or implemented.

Especially note the way the copy constructor is implemented: its purpose is to insure that your code properly defines certain functions to accept parameters that are passed by-reference instead of by-value. Any attempt to pass a Vec3 object by-value will invoke this copy constructor - and that should never happen.

Getters and setters for x, y and z are also defined and implemented already.

Make sure your copies are working:

bash-4.2$ make
g++ -Wall main.cpp vec.cpp -o main
bash-4.2$ ./main
From default constructor: 0 0 0
From 3-param constructor: 5.5 6.6 7.7

For each of the remaining steps, you must (a) add definitions to vec.h, (b) implement these enhancements in vec.cpp, and (c) uncomment code in main.cpp that tests it. Then compile with make, and execute to verify results are correct before continuing to the next step.

Step 2: Overload << for cout (and streams of its kind)

The goal is to make the << operator work to output the values of a Vec3 object's x, y and z data to an ostream object like cout like so:

(x, y, z)

Of course, x, y, and z should be replaced by their double values. For example, given the initial values of the vector created with the 3-param constructor, vec_1, the following statement ...

cout << vec_1 << endl;

... should print this:

(5.5, 6.6, 7.7)

This function should be declared in vec.h as a non-member function that is a "friend" of class Vec3. The function should take two parameters: an ostream& and a const Vec3&. It should return the ostream as a reference variable. And the function's name must be operator<<.

Define the function now in vec.h, and implement it in vec.cpp. Then uncomment the first two lines that test it in main.cpp (20-21 in the original), compile and execute. Results should match the following exactly:

From default constructor: 0 0 0
From 3-param constructor: 5.5 6.6 7.7
From default constructor: (0, 0, 0)
From 3-param constructor: (5.5, 6.6, 7.7)

Step 3: Overload >> for cin (and other istreams)

Now define operator>>: to retrieve new data for a Vec3 object from an istream& like cin. Declare it in vec.h (it looks very much like the operator<< you created in the last step), and implement it in vec.cpp. Notice that main.cpp already prompts the user to enter 3 double values, so your function should just read the data and not prompt the user again. You should return the istream object as a reference variable. Why?

Uncomment the lines in main.cpp that test this feature (25-27 in the original), compile again, and execute. You should be able to enter 3 doubles, and verify they are printed in the last line of output. For convenience, you can run your program via the following command to avoid having to retype the numbers each time:

echo "1.1 2.2 3.3" | ./main

The output looks a bit funny that way, but it's worth it if you must test many times.

Step 4: Overload + for adding two Vec3 instances

IMPORTANT: You must begin working on this step, but you don't have to complete it to earn full credit. Please try to finish it and Step 5, but if you are running out of time before lab ends, then move on to Step 6 - the TA will check off your work even if it is not exactly correct, as long as you can show evidence that you tried. Be prepared to answer questions about your attempts.

Now you will need to overload "+" so that you can add two Vec3 instances, to create a third Vec3 instance. Think about what the parameters should be and what the return value should be. Vec3 objects are added by adding their individual components together. For example, `Vec3(1, 2, 3) + Vec3(4, 5, 6)` should produce `Vec3(5, 7, 9)`.

And like the others, this function should be a non-member function, but it should also be a friend of the class. Why? Because it involves more than one object again, in fact three of them this time.

Test this new functionality as before.

Step 5: Overload * to multiply a Vec3 instance by a double value

This function should create a Vec3 object that contains multiples of all the components of another Vec3 object. Specifically, each component of the Vec3 should be multiplied by the value of the double. For example, `Vec3(1, 2, 3) * 4` should produce `Vec3(4, 8, 12)`.

Again there is more than one object being handled by the function. What is the implication of that fact? Right: it means this function should be a non-member function too. (Don't worry: the "After lab work" includes a member operator, and the homework includes more.)

Get it working and test it after uncommenting the last two statements in main.cpp. By now you should be able to successfully run the complete `main.cpp` program. Given the command listed in step 3, `main` should produce the following output:

bash-4.2$ echo "1.1 2.2 3.3" | ./main
From default constructor: 0 0 0
From 3-param constructor: 5.5 6.6 7.7
From default constructor: (0, 0, 0)
From 3-param constructor: (5.5, 6.6, 7.7)
Input three doubles: Updated using >> overloading: (1.1, 2.2, 3.3)
The previous two added together: (6.6, 8.8, 11)
More addition: (13.2, 17.6, 22)
Simple multiplication: (8.8, 17.6, 26.4)
More multiplication: (6.6, 13.2, 19.8)

Step 6: Show off your work and get credit for the in-lab requirements

Get your TA's attention to inspect your work, and to record completion of your in-lab work.

Don't leave early though ... begin the after-lab work below.

Step 6a. ONLY IF YOU RAN OUT OF TIME TO HAVE THE TA INSPECT YOUR WORK
(or if the TA tells you that he wants you to turn in)

If you must complete this assignment at CSIL, then submit it with the turnin program - but do NOT turn it in if the TA already checked you off and did not give specific instructions to turn in. You MUST have both your name and your partner's name in the file in order to receive credit. Remember that the original pilot needs to do this step, since that is whose account you have been using in Cooper Lab.

Bring up a terminal window on CSIL, and cd into the original pilot's cs32 directory, and cd again into the lab06 directory. Then type the following to turn in vec.h and vec.cpp:

turnin lab06@cs32 vec.h vec.cpp

Evaluation and Grading

Each pair of students must accomplish the following to earn full credit for this lab:


After lab-work is done

Optional - or to do in lab after completing the required work

Each of the following items add functionality to the Vec3 class, meaning they require additions to both vech.h and vec.cpp, like the required steps above. Use the second testing program, main2.cpp. As before, uncomment the appropriate parts when you are ready to test them.

Add a couple more non-member, binary operator functions

First overload operator* again, this time so it will allow the double value to be on the left side of the expression, as in `4 * vec_0` instead of the reverse. (You knew the current version won't work that way now, right?) This function can be easily implemented by using the existing operator* function. Here are the expected results from testing this part with ./main2:

bash-4.2$ echo "1.1 2.2 3.3" | ./main2
Input three doubles: Input vector: (1.1, 2.2, 3.3)
Constant vector: (5.5, 6.6, 7.7)
Simple multiplication: (8.8, 17.6, 26.4)
More multiplication: (6.6, 13.2, 19.8)

Now add a binary operator- function to subtract the right-side argument from the left-side one. You can implement it by using the existing operator+ and operator* functions: a-b is the same as a+(-1*b). Results should match the following (continued from ./main2 run above):

Input vector - const vector: (-4.4, -4.4, -4.4)
More subtraction: (-11, -13.2, -15.4)

Add a member, unary operator*= function

When invoked, the Vec3 object must appear on the left side of the expression - the idea is to multiply the x, y and z data of this object all by the same double value. This double value will be the function's only argument, and so it is necessary to make this function a member of the class - that way, the pointer named this will be passed to it automatically, giving the function immediate access to x, y and z. The function should return a Vec3& - the same object upon which it was called. Do you remember the name of the calling object? Well if this is the pointer, then what is the object? The ./main2 results for this part are as follows:

Input vector after *= 2: (2.2, 4.4, 6.6)
Last result *=.5: (1.1, 2.2, 3.3)

Homework - to be done before lab next week: November 15

This week's homework includes adding features to class Vec3 and testing them, as described in these hw3 instructions. You will use the turnin program to submit some of the work, and that must be done before your next lab - the TA will check for it then. A written part is also required, to be turned in at your lab next week. Please do NOT print the homework in Cooper Lab.

Each student must complete the paper part of the homework, even if you do the programming parts in pairs.

Here are the continued results from the ./main2 runs above, after all of the homework parts are completed:

Input vec += constant vec: (6.6, 8.8, 11)
     Verify still changed: (6.6, 8.8, 11)
++(Last vec) : (7.6, 9.8, 12)
  Verify same: (7.6, 9.8, 12)
(Last vec)++ : (7.6, 9.8, 12)
  Verify diff: (8.6, 10.8, 13)
Constant's data: 5.5 6.6 7.7
Final vec: (77.77, 77.77, 77.77)

Prepared by Michael Costanzo, heavily based on a lab by Bryce Boe (summer 2012 instructor).