The purpose of this assignment is to give you some experience in dynamic memory
ID: 3530741 • Letter: T
Question
The purpose of this assignment is to give you some experience in dynamic memory allocation and all that that entails. It should also give you a bit of additional experience in operator overloading.
You will need to write a single class for this assignment, the VectorN class. You will need to implement several methods and functions assoicated with this class.
The class should be implemented as two separate files. The class definition should be placed in an appropriately named header (.h) file. The implementations of the class methods and any other associated functions should be placed in a separate .cpp file for the class.
Data members
This class contains a dynamically allocated array of floating point data values. Because the array is allocated dynamically, an integer value is also maintained inside the class to determine the number of elements in the array.
Methods and associated functions
Constructors
The class should have several constructors. One constructor, the default constructor, should take no arguments and initialize the vector to hold no data. Another constructor should take two arguments, the first being an array of floats to be copied into the vector and the second an integer count of how many elements are in the array.
Destructor
Any class that has dynamic memory should have a destructor.
Copy constructor
The class should also have a proper copy constructor.
operator=
The assignment operator should be properly overloaded.
operator<<
The output operator should be overloaded so that a VectorN can be sent to the standard output. An empty vector (size 0) should be printed as ().
clear()
This method should properly set the instance back to a vector of zero elements.
size()
Returns the size of the vector; i.e., the number of elements in the dynamically-allocated array.
operator+
The addition operator should be overloaded to take two VectorNs and return a VectorN. The components of the result are computed by simply adding the components of the operands. For example (1, 2, 3) + (4, 5, 6) should have a result of (5, 7, 9). The operands should not be altered. If the operands are of different sizes then the result should be the size of the smallest operand. For example, (1, 2, 3) + (4, 5) should have a result of (5, 7).
Implementation Hint: In any of the arithmetic operators, if you use a local VectorN variable to hold temporary results, it will probably be necessary to first create an empty VectorN and then directly manipulate the vector array pointer to allocate memory for the vector array.
operator-
The binary subtraction operator should also be overloaded to take two VectorNs and return a VectorN. The result is the component-wise difference of the operands. For example (1, 2, 3) - (4, 6, 8) should have a result of (-3, -4, -5). As with addition, the result should have the size of the smallest operand.
operator*
The binary multiplication operator should be overloaded three times. The first form, called the scalar product takes two VectorNs and produces a single floating point value. The scalar product is computed by multiplying the corresponding components of the two vectors and adding the results. For example the scalar product of (1, 2, 3) and (4, 5, 6) is (1
Explanation / Answer
Because when instantiating a template, the compiler creates a new class with the given template argument. For example:
When reading this line, the compiler will create a new class (let's call it FooInt), which is equivalent to the following:
Consequently, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument (in this case int). If these implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template.
A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.
This way, implementation is still separated from declaration, but is accessible to the compiler.
Another solution is to keep the implementation separated, and explicitly instantiate all the template instances you'll need:
124 down vote acceptedBecause when instantiating a template, the compiler creates a new class with the given template argument. For example:
template<typename T> struct Foo { T bar; void doSomething(T param) { // do stuff using T } }; // somewhere in a .cpp Foo<int> f; When reading this line, the compiler will create a new class (let's call it FooInt), which is equivalent to the following:
struct FooInt { int bar; void doSomething(int param) { // do stuff using int } } Consequently, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument (in this case int). If these implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template.
A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.
// Foo.h template <typename T> struct Foo { void doSomething(T param); }; #include "Foo.tpp" // Foo.tpp template <typename T> void Foo<T>::doSomething(T param) { //implementation } This way, implementation is still separated from declaration, but is accessible to the compiler.
Another solution is to keep the implementation separated, and explicitly instantiate all the template instances you'll need:
// Foo.h // no implementation template <typename T> struct Foo { ... }; //---------------------------------------- // Foo.cpp // implementation of Foo's methods // explicit instantiations template class Foo<int>; template class Foo<float>; Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.