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
Vector
class and its associated functions should be defined within the namespacevector374
. - Internally, a
Vector
is represented as an array of threefloats
corresponding to the magnitudes in thex
,y
, andz
directions (at indices 0, 1, and 2 respectively). - This array must be dynamically allocated on the heap when a
Vector
instance is created, and properly deleted when theVector
is destroyed or no longer in use.
Constructors/Destructor¶
You will implement three constructors:
- A default (0-argument) constructor that initializes a
Vector
to(0, 0, 0)
. - A constructor with three
float
parameters that sets the initial values for thex
,y
, andz
magnitudes. - A copy constructor that creates a new
Vector
as 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 += v
andu -= 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 instancesv1
andv2
, the expressionv1 + v2
should return a newVector
whose components are the element-wise sums ofv1
andv2
. - Similarly, you should overload the
-
operator to perform vector subtraction. Given two Vector instancesv1
andv2
, the expressionv1 - v2
should return a newVector
whose components are the element-wise differences ofv1
andv2
. - The operator
*
should compute the inner product (dot product) of twoVector
s. - For example, if
v1 = (a,b,c)
andv2 = (d,e,f)
, thenv1 * v2
should return the scalar valuea * d + b * e + c * f
as afloat
. - The operator
*
should also be overloaded to perform scalar multiplication so that ifv
is aVector
(a,b,c)
andk
is afloat
, then bothv * k
andk * v
return newVector
s with each component ofv
multiplied byk
– i.e.,(a * k, b * k, c * k)
. - You should create a function called
cross
that computes the cross product of twoVector
s and returns a newVector
instance representing the cross product. The below image shows the formula for computing a cross product of two 3D vectorsA
andB
:
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¶
Vector
s 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 abool
ean (i.e.,true
orfalse
).- Two
Vector
s 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 == v2
ifa == d && b == e && c == f
. - Two
Vector
s 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 != v2
ifa != 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¶
Vector
should define alength
function that computes and returns the magnitude of the vector as afloat
. For a vector with components(a,b,c)
, thelength
is computed by:√( a^2 + b^2 + c^2)
.- You may use
std::sqrt
and/orstd::pow
to implement this function. - The class should also define stream output by overloading the
<<
operator so that writings << v
outputs the Vectorv
to the output streams
in the format(a,b,c)
. Thex
,y
,z
components should be separated by commas with no spaces, and surrounded by one pair of parentheses. No trailing newline orstd::endl
should 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
Vector
members.
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 Vector
s. This means actual Vector
values, not pointers or references to Vector
s 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.