CSE 333 Exercise 6
Due: Wednesday, October 28 by 11 AM
Rating: 4 (note)
Each exercise this quarter is rated on a integer scale of 1 – 5, inclusive, with 1 being the "least time-consuming" and 5 being the "most time-consuming".
This difficulty scale is meant as a rough guide for you in predicting the amount of time to set aside for each exercise as you balance the work required for 333 with your other obligations. However, it is necessarily imperfect as everyone's set of circumstances and experiences with the exercises differ. If your experience with an exercise does not align with its rating, that is not a reflection of you or your abilities.
Goals
- Write your first C++ class – data members, methods, and access specifiers.
- Examine the effects of pass-by-value and pass-by-reference in C++ on function arguments and return values.
- Define the behavior of standard operators for a user-defined class.
Background
A major addition in C++ compared to C is the introduction of classes! However, there are lots of new stylistic considerations to properly encapsulate these classes, including:
- Const and non-const variables, parameters, and return values,
- Reference vs. non-reference parameters and return values,
- The presence or absence of constructors, destructors, and operators, and
- Member vs. non-member functions. [saved for Exercise 7]
In this exercise, we will put most of these pieces together while writing your first C++ class; carefully consider why each of these different pieces is important!
Problem Description
Create and test a C++ class Vector that implements
3-D vectors in the following two files:
Vector.h: A header file that declares a classVectorwith the following properties:- The representation of a
Vectorshould be threefloats giving the magnitudes in the x, y, and z directions. - The following constructors should be present:
- a default (i.e., 0-argument) constructor that
initializes a
Vectorto (0,0,0), - a constructor with 3 floats as parameters giving initial values for the x, y, and z magnitudes (in that order), and
- a copy constructor.
- a default (i.e., 0-argument) constructor that
initializes a
- There should be a destructor that does whatever work is
needed when a
Vectorobject is deleted. If no work is needed, the body of the destructor can be empty. - The class should define assignment on vectors
(
u = v). - The class should define getters
get_x,get_yandget_zthat return the corresponding values. - The class should define updating assignments on vectors
(
u += vandu -= v) that perform element-by-element addition or subtraction of theVectorcomponents. - Operator * should compute the inner product
(i.e., the dot product) of two
Vectors as afloat. Ifv1 = (a,b,c)andv2 = (d,e,f), thenv1 * v2should return the scalar valuea*d + b*e + c*f.
- The representation of a
Vector.cc: A file containing the implementation of theVectorclass.
In addition, you should create the following two files for testing
and compiling your Vector class:
Makefile: The commandmakeshould compile the source files as needed to create an executable program namedex6. The commandmake cleanshould remove theex6executable file, all.ofiles, and any editor or other backup files whose names end in~(e.g.,ex6.cc~).ex6.cc: A file containing amainfunction that tests theVectorobject. There are two types of tests you should do in this file:- Tests that verify the correct behavior of
the defined constructors and operators of your
Vectorclass. For this part of the tests, make sure you utilize the status code to perform proper automated testing as you did in Exercise 3. - After testing the behavior of the
constructors and operators, test the behavior of how objects
and references are passed in C++.
To do this, create two additional functions:
Increment(), which accepts an instance of aVector(not a pointer or reference to aVector) as an argument, and increments the values stored in the vector by one.VerifyAddress(), which accepts aVectorreference and avoid*as arguments, and returnstrueif the address of the aliasedVectorhas the same numeric value as the passed-invoid*. It should returnfalseif they are not the same integral value.
For these tests, you should create an instance of
Vectorand then:- Call
Increment()to determine whether theVectorobject itself was passed by value or passed by reference toIncrement()(i.e., your code should make this determination based on the result of the call; don't hard-code the output).- If it was passed by value, print out on a new line:
Vector: pass-by-value - If it was passed by reference, print out on a new line:
Vector: pass-by-reference
- If it was passed by value, print out on a new line:
- Call
VerifyAddress()to determine whether themain()instance ofVectoris the same instance as the one visible toVerifyAddressby comparing their addresses.- If they are the same (i.e.,
VerifyAddressreturnedtrue), print out on a new line:Ref: same address - If
falseis returned, print out on a new line:Ref: different address
- If they are the same (i.e.,
Note that neitherIncrement()norVerifyAddress()should print the tests results; they should be printed frommainas the last two lines of your output.
- Tests that verify the correct behavior of
the defined constructors and operators of your
Implementation Notes
Memory
No dynamic allocation should be necessary for the completion of
this exercise (i.e., do NOT use new,
delete, malloc, or free).
Testing
For the purposes of this exercise, it is enough for you to write
code that makes use of each of the constructors, operators, and
other functions that you wrote and verifies that the
Vector members contain the correct values at each
step.
Be sure that if an error is encountered during testing, that the
testing code handles it appropriately.
Since there is a significant amount of functionality to test, you
should write static helper functions to factor out
redundant code.
Makefile
Your Makefile should contain intermediate .o files for
each .cc file that will be compiled into the
executable.
Your Makefile should also set dependencies correctly such that it
only recompiles individual files and rebuilds the program when
needed, and should reuse any existing .o files or
other files that are already up to date.
Test Suite
We have provided a test suite executable in your GitLab repo that can help you check just the output correctness of your code (i.e., it does not check style or memory). This test suite is purposely opaque and will not reveal what is failing. You should aim to see the following output:
$ ./test_ex6 Test cases purposely not revealed. 0 failed
Style Focus
Classes
This is your first exercise with classes, and you should be sure
you are following the best standards with commenting and organizing
your classes as laid out in lecture.
Make sure that you have comments with their declaration in the
header file, and have an overall comment describing the behavior of
theVectorclass.
Const
Functions, parameters, and variables should be labeled with
const appropriately throughout your program.
Refer to the lecture material for best practices.
Submission
Submit the following file(s) by creating an ex6-submit tag in your repo before the assignment deadline. The file(s) should be located in the exact directory listed below, including capitalization:
ex6/Vector.hex6/Vector.ccex6/ex6.ccex6/Makefile
For full credit, your code must:
- Compile without errors or warnings on CSE Linux machines
(lab workstations,
attu, or CSE home VM). - Have no runtime errors, memory leaks, or memory errors
(
g++andvalgrind). - Be contained in the files listed above with your Makefile
compiling your code with the
g++options-Wall -g -std=c++17. - Have a comment at the top of your
.ccand.hfiles with your name(s) and CSE or UW email address(es). - Be pretty: the formatting, modularization, variable and
function names, commenting, and so on should be consistent with
class style guidelines.
Additionally, the linter shouldn't have any complaints about your
code (
cpplint.py). - Be robust: your code should deal with hard-to-handle/edge cases and bogus user input (if there are any) gracefully.