I plan to implement a simple simulation in C++, which requires mathematical vectors. The following header file contains the complete vector class with all it's method definitions. By overloading several operators, I tried to make the class more usable. For example: the components of the vector can be modified using v[0] = 5; instead of using v.set(0, 5);.
Nervetheless, the header file seems quite long and the class could probably be rewritten in a modern way. Additionally, some vector operations could parallelized. Any tips for improving the code quality and performance?
Header file:
#ifndef __COLUMNVECTOR_H__
#define __COLUMNVECTOR_H__
#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>
#include <stdexcept>
template <typename T>
class ColumnVector
{
public:
const unsigned int DIMENSION;
private:
std::vector<T> entries;
public:
ColumnVector(unsigned int);
ColumnVector(const std::vector<T> &);
T &operator[](unsigned int);
bool operator==(const ColumnVector<T> &) const;
bool operator!=(const ColumnVector<T> &) const;
ColumnVector<T> operator+(const ColumnVector<T> &) const;
ColumnVector<T> operator-(const ColumnVector<T> &) const;
ColumnVector<T> &operator+=(const ColumnVector<T> &);
ColumnVector<T> &operator-=(const ColumnVector<T> &);
T operator*(const ColumnVector<T> &)const;
private:
bool equals(const ColumnVector<T> &) const;
};
template <typename T>
ColumnVector<T>::ColumnVector(unsigned int d) : DIMENSION(d),
entries(d)
{
}
template <typename T>
ColumnVector<T>::ColumnVector(const std::vector<T> &v) : DIMENSION(v.size()),
entries(v)
{
}
template <typename T>
T &ColumnVector<T>::operator[](unsigned int i)
{
if (i >= DIMENSION)
{
throw std::out_of_range("Not enough dimensions!");
}
return entries[i];
}
template <typename T>
bool ColumnVector<T>::equals(const ColumnVector<T> &o) const
{
return (DIMENSION == o.DIMENSION) &&
(entries == o.entries);
}
template <typename T>
bool ColumnVector<T>::operator==(const ColumnVector<T> &o) const
{
return *this.equals(o);
}
template <typename T>
bool ColumnVector<T>::operator!=(const ColumnVector<T> &o) const
{
return !*this.equals(o);
}
template <typename T>
ColumnVector<T> ColumnVector<T>::operator+(const ColumnVector<T> &o) const
{
if (DIMENSION != o.DIMENSION)
{
throw std::length_error("Dimensions must be equal!");
}
ColumnVector<T> result(DIMENSION);
std::transform(entries.begin(), entries.end(),
o.entries.begin(), result.entries.begin(),
std::plus<T>());
return result;
}
template <typename T>
ColumnVector<T> ColumnVector<T>::operator-(const ColumnVector<T> &o) const
{
if (DIMENSION != o.DIMENSION)
{
throw std::length_error("Dimensions must be equal!");
}
ColumnVector<T> result(DIMENSION);
std::transform(entries.begin(), entries.end(),
o.entries.begin(), result.entries.begin(),
std::minus<T>());
return result;
}
template <typename T>
ColumnVector<T> &ColumnVector<T>::operator+=(const ColumnVector<T> &o)
{
if (DIMENSION != o.DIMENSION)
{
throw std::length_error("Dimensions must be equal!");
}
std::transform(entries.begin(), entries.end(),
o.entries.begin(), entries.begin(),
std::plus<T>());
return *this;
}
template <typename T>
ColumnVector<T> &ColumnVector<T>::operator-=(const ColumnVector<T> &o)
{
if (DIMENSION != o.DIMENSION)
{
throw std::length_error("Dimensions must be equal!");
}
std::transform(entries.begin(), entries.end(),
o.entries.begin(), entries.begin(),
std::minus<T>());
return *this;
}
template <typename T>
T ColumnVector<T>::operator*(const ColumnVector<T> &o) const
{
if (DIMENSION != o.DIMENSION)
{
throw std::length_error("Dimensions must be equal!");
}
std::vector<T> multiplied(DIMENSION);
std::transform(entries.begin(), entries.end(),
o.entries.begin(), multiplied.begin(),
std::multiplies<T>());
return std::accumulate(multiplied.begin(), multiplied.end(), 0);
}
#endif
Usage example:
#include <iostream>
#include "ColumnVector.h"
using namespace std;
int main()
{
ColumnVector<int> cv(std::vector<int>{1, 2, 3});
ColumnVector<int> cv2(std::vector<int>{1, 2, 3});
cout << cv * cv2 << "\n" << cv + cv2 << endl;
}