You will implement a C++ class called Vector that represents 3D vectors in space (i.e., vectors with x, y, and z components – not to be confused with std::vector).
Boilerplate files for Vector.h and Vector.cc are provided; your task is to fully implement these files.
A demo program called hw7.cc is also provided to test your Vector implementation. You will need to update several function calls in hw7.cc to match your implementation choices. Note that hw7.cc will only compile completely once your Vector class is fully implemented, so feel free to comment out portions of hw7.cc as you incrementally test your code.
A Makefile is not provided. You will need also need to create a Makefile to compile Vector.cc and hw7.cc to run your program. Your Makefile should compile the code with the g++ options -g -Wall -std=c++17.
Vector Properties¶
You will implement the Vector class with the following properties:
- The
Vectorclass and its associated functions should be defined within the namespacevector374. - Internally, a
Vectoris represented as an array of threefloatscorresponding to the magnitudes in thex,y, andzdirections (at indices 0, 1, and 2 respectively). - This array must be dynamically allocated on the heap when a
Vectorinstance is created, and properly deleted when theVectoris destroyed or no longer in use.
Constructors/Destructor¶
You will implement three constructors:
- A default (0-argument) constructor that initializes a
Vectorto(0, 0, 0). - A constructor with three
floatparameters that sets the initial values for thex,y, andzmagnitudes. - A copy constructor that creates a new
Vectoras a copy of an existing one.
You should also implement a destructor that performs any necessary cleanup when a Vector object is deleted. If no cleanup is required, the destructor body may be left empty.
Assignment/Updating Assignment Operators¶
- The class should define assignment for vectors (
u = v). - The class should also define the updating assignment operators
+=and-=(i.e.,u += vandu -= v). These operators must perform element-by-element addition or subtraction of the vector components, respectively. - These assignment operators should modify the vector they are used on – in this case, vector
u.
Mathematical Operators¶
- You should overload the
+operator to perform vector addition. Given two Vector instancesv1andv2, the expressionv1 + v2should return a newVectorwhose components are the element-wise sums ofv1andv2. - Similarly, you should overload the
-operator to perform vector subtraction. Given two Vector instancesv1andv2, the expressionv1 - v2should return a newVectorwhose components are the element-wise differences ofv1andv2. - The operator
*should compute the inner product (dot product) of twoVectors. - For example, if
v1 = (a,b,c)andv2 = (d,e,f), thenv1 * v2should return the scalar valuea * d + b * e + c * fas afloat. - The operator
*should also be overloaded to perform scalar multiplication so that ifvis aVector(a,b,c)andkis afloat, then bothv * kandk * vreturn newVectors with each component ofvmultiplied byk– i.e.,(a * k, b * k, c * k). - You should create a function called
crossthat computes the cross product of twoVectors and returns a newVectorinstance representing the cross product. The below image shows the formula for computing a cross product of two 3D vectorsAandB:
![If A = [a,b,c] and B = [d,e,f] then A x B = (b*f - c*e, c*d - a*f, a*e - b*d)](https://courses.cs.washington.edu/courses/cse374/25su/homeworks/hw7/imgs/crossproduct.png)
Note
It would be nice to use the x operator since it visually resembles the cross product symbol, but C++ only allows certain operators to be overloaded. And unfortunately, the letter x is not one of them. Therefore, creating a function named cross is the best alternative.
- All these mathematical operators should not modify the original vectors they are used on. Instead, they should create and return a new Vector instance representing the result. (With the exception of the dot product operator, which should return a scalar value.)
Comparison Operators¶
Vectors should be compared using the==(equals) and!=(not equals) operators. These must perform value comparison rather than object equality (i.e., being the same exact object in memory). The result of these operators should be aboolean (i.e.,trueorfalse).- Two
Vectors are equal if each of their corresponding components are exactly equal. That is, if you have a vectorv1 = (a,b,c)and vectorv2 = (d,e,f)thenv1 == v2ifa == d && b == e && c == f. - Two
Vectors are not equal if at least one pair of corresponding components differ. That is, if you have a vectorv1 = (a,b,c)and vectorv2 = (d,e,f)thenv1 != v2ifa != d || b != e || c != f.
Note
Typically, it is not recommended to compare floating-point values using == or != due to rounding errors that can cause unexpected results. However, for the purposes of this assignment, it is ok to use these comparisons because we will not be testing with edge-case floating-point values. That said, in real-world applications, using direct equality checks on floats is generally discouraged!
Other¶
Vectorshould define alengthfunction that computes and returns the magnitude of the vector as afloat. For a vector with components(a,b,c), thelengthis computed by:√( a^2 + b^2 + c^2).- You may use
std::sqrtand/orstd::powto implement this function. - The class should also define stream output by overloading the
<<operator so that writings << voutputs the Vectorvto the output streamsin the format(a,b,c). Thex,y,zcomponents should be separated by commas with no spaces, and surrounded by one pair of parentheses. No trailing newline orstd::endlshould be added.
Any accessors and or mutators (getters and setters) as needed¶
- You will need public getter methods if non-member and non-friend functions need access to
Vectormembers.
Tip
You have the flexibility to decide whether each function or operator should be implemented as a member function, non-member function, friend function, or non-friend function, as long as the functions behave correctly and as intended.
Refer to lecture materials for guidance and tips on how to determine the appropriate type for each function.
Note
Several of these functions are required to return new Vectors. This means actual Vector values, not pointers or references to Vectors that have been allocated elsewhere.
Expected Output¶
Once you have completed your implementations of the Makefile, Vector.h, and Vector.cc (and have updated hw7.cc to correctly call your necessary functions), you should run the program using ./hw7 and expect to see the following output:
default Vector v1, should be (0,0,0): (0,0,0)
Vector v2 with initial values, should be (1,2,3): (1,2,3)
Vector v3 from copy constructor, should be (1,2,3): (1,2,3)
Vector assignment, should have three copies of (3.1,-2.5,2.7):
v1: (3.1,-2.5,2.7) v3: (3.1,-2.5,2.7) v4: (3.1,-2.5,2.7)
Dot product:
(1,2,3) * (1,2,3) = 14
(3.1,-2.5,2.7) * (1,2,3) = 6.2
Scalar product:
(3.1,-2.5,2.7) * 2 = (6.2,-5,5.4)
-3.2 * (3.1,-2.5,2.7) = (-9.92,8,-8.64)
Update assignment:
v1 += v2; v1 is now: (4.1,-0.5,5.7)
v1 -= v2; v1 is now: (3.1,-2.5,2.7)
Sum:
(1.2,3.4,-5.6) + (-2.1,4.3,6.5) = (-0.9,7.7,0.9)
Difference:
(-2.1,4.3,6.5) - (1.2,3.4,-5.6) = (-3.3,0.9,12.1)
Cross product:
(1.2,3.4,-5.6) x (-2.1,4.3,6.5) = (46.18,3.96,12.3)
Length:
|(1.2,3.4,-5.6)| = 6.66033
|(-2.1,4.3,6.5)| = 8.07156
Equals:
(1.2,3.4,-5.6) == (-2.1,4.3,6.5) : false
(1.2,3.4,-5.6) == (1.2,3.4,-5.6) : true
(3.1,-2.5,2.7) == (3.1,-2.5,2.7) : true
Not Equals:
(1.2,3.4,-5.6) != (-2.1,4.3,6.5) : true
(1.2,3.4,-5.6) != (1.2,3.4,-5.6) : false
(3.1,-2.5,2.7) != (3.1,-2.5,2.7) : false
Your submission will be assessed based on output correctness. The autograder will compare your program’s output from hw7.cc line by line against the expected output.
A correct implementation must match the expected output exactly.
Please do not attempt to hard-code the output; staff will verify that your output is produced through the proper implementation and usage of the Vector class.
Linting¶
We have included cpplint.py which you should run to style check your C++ code for both Vector.h and Vector.cc. The autograder will run it on your code as well.
Warning
cpplint may generate warnings about the header guard naming in Vector.h. To suppress these warnings, we have included comments with // NOLINT. Please do not remove these comments.
Memory Errors¶
Your code should be memory-error free – to test this, you can run valgrind on the produced hw7 executable, just like how you run valgrind with C executables: valgrind --leak-check=full ./hw7.
Tips¶
You can refer to the Complex class examples from lecture to review C++ class syntax and conventions. You may find it helpful to start with that code and modify it as needed to use the new array representation for the Vector data and make other necessary changes.
You will submit your implementations of Vector.h, Vector.cc, your modified version of hw7.cc that matches the expected output, and your Makefile to Gradescope via Gitlab.