Overloading Operator *= and Operator+ in Matrix Template Class - c++

The method template <class T> const Matrix<T> &Matrix<T>::operator*=(T rhs) for program matrix.cc should be able to returns calling object with matrix scaled by rhs, and the parameter rhs will be the same type as the matrix.
The error output that I am receiving from the compiler is:
[hw7] make clean && make bin/test_matrix_mul_assign && ./bin/test_matrix_mul_assign
rm -f bin/*
g++ -std=c++11 -Wall -I inc -I src -c src/test_matrix_mul_assign.cc -o bin/test_matrix_mul_assign.o
g++ bin/test_matrix_mul_assign.o -o bin/test_matrix_mul_assign
Testing Matrix::operator*=
Expected Matrix[0][0]: 2.0, Actual: 1
FAILED
Could someone let me know why I receive this "Failed" output when I know I pass the // TEST MUL ASSIGMENT OP CORRECT RETURN section.
Here is my matrix.cc:
#include <matrix.h>
template <class T>
const Matrix<T> &Matrix<T>::operator*=(T rhs) {
unsigned int rows_ = 0;
unsigned int cols_ = 0;
T **m_ = nullptr;
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = m_[i][j] * rhs;
}
}
return *this;
}
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const {
if (!(this->cols_ == rhs.cols_) && (this->rows_ == rhs.rows_)) {
std::cout << "Cannont add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
for (unsigned int i = 0; i < lhs.rows; ++i) {
for (unsigned int j = 0; j < lhs.cols_; ++j) {
lhs[i] += rhs[i];
}
}
return lhs;
}
Here is my matrix.h:
#include <cassert>
// using assert
#include <exception>
#include <iostream>
template <class T>
class Matrix {
public:
friend class MatrixTester;
/* Times Equals Op: 1 Point
* Returns calling object with matrix scaled by rhs.
* Parameter:
* - rhs will be the same type as the matrix
*/
const Matrix<T> &operator*=(T rhs);
/* Add Op: 1 Point
* Returns the sum of calling object's matrix and rhs's matrix as a new
* object.
* Precondition(s):
* - lhs rows must equal rhs rows
* - lhs cols must equal rhs cols
*/
const Matrix<T> operator+(const Matrix<T> &rhs) const;
private:
T **m_;
unsigned int rows_;
unsigned int cols_;
};
#include <matrix.cc> //NOLINT
This is my test_matrix_mul_assign.cc tester:
#include <test_matrix.h>
int main(int argc, char **argv) {
MatrixTester tester;
cout << "Testing Matrix::operator*=" << endl;
if (tester.Test_MulAssignOp()) {
cout << " PASSED" << endl;
return 0;
}
cout << " FAILED" << endl;
return 1;
}
bool MatrixTester::Test_MulAssignOp() const {
const int kRows = 3, kCols = 4;
Matrix<double> test_m;
test_m.m_ = new double *[kRows];
for (unsigned int i = 0; i < kRows; ++i) {
test_m.m_[i] = new double[kCols];
for (unsigned int j = 0; j < kCols; ++j)
test_m.m_[i][j] = (i + 1.0) * (j + 1.0);
}
test_m.rows_ = kRows;
test_m.cols_ = kCols;
// TEST MUL ASSIGMENT OP CORRECT RETURN
const Matrix<double> *m_ptr = &(test_m *= 2.0);
if (m_ptr != &test_m) {
cout << " Expected return address of assigment: " << &test_m
<< ", Actual: " << m_ptr << endl;
return false;
}
// TEST MUL ASSIGMENT OP CALCULATION
if (test_m.m_[0][0] != 2.0) {
cout << " Expected Matrix[0][0]: 2.0, Actual: " << test_m.m_[0][0] << endl;
return false;
}
if (test_m.m_[1][3] != 16.0) {
cout << " Expected Matrix[1][3]: 16.0, Actual: " << test_m.m_[1][3]
<< endl;
return false;
}
if (test_m.m_[2][2] != 18.0) {
cout << " Expected Matrix[2][2]: 18.0, Actual: " << test_m.m_[2][2]
<< endl;
return false;
}
return true;
}

You have the following variable definitions in the operator*= implementation:
unsigned int rows_ = 0;
unsigned int cols_ = 0;
T **m_ = nullptr;
They will shadow all of the members of the class. When you use rows_, cols_ and m_ later in the function definition they will refer to these local variables, not the class members of the current instance.
Therefore effectively your implementation of operator*= does nothing at all. It is not surprising that the test for the correct value then fails.
Simply remove these declarations, so that the names will refer to the current instance's members instead.
Then there is also not going to be any point to m_[i] = new T[cols_];. So remove that as well.
Why are there all of these dynamic allocations with new in the first place? This is seriously bad style and is going to cause you all kinds of issues. Use std::vector instead.
class Matrix also seems to be lacking a proper constructor. This again will cause all kinds of issues, especially when it leaves memory allocation to a user of the class.

Related

Operator Overloading Matrix Multiplication

The issue I am having is how to get the correct number columns to go through for the inner most loop of K.
An example is a 2x3 matrix and a 3x2 matrix being multiplied.
The result should be a 2x2 matrix, but currently I dont know how to send the value of 2 to the operator overloaded function.
It should be
int k = 0; k < columns of first matrix;k++
Matrix::Matrix(int row, int col)
{
rows = row;
cols = col;
cx = (float**)malloc(rows * sizeof(float*)); //initialize pointer to pointer matrix
for (int i = 0; i < rows; i++)
*(cx + i) = (float*)malloc(cols * sizeof(float));
}
Matrix Matrix::operator * (Matrix dx)
{
Matrix mult(rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
mult.cx[i][j] = 0;
for (int k = 0; k < ?;k++) //?????????????
{
mult.cx[i][j] += cx[i][k] * dx.cx[k][j];
}
}
}
mult.print();
return mult;
//calling
Matrix mult(rowA, colB);
mult = mat1 * mat2;
}
Linear algebra rules say the result should have dimensions rows x dx.cols
Matrix Matrix::operator * (Matrix dx)
{
Matrix mult(rows, dx.cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
mult.cx[i][j] = 0;
for (int k = 0; k < cols;k++) //?????????????
{
mult.cx[i][j] += cx[i][k] * dx.cx[k][j];
}
}
}
mult.print();
return mult;
A few random hints:
Your code is basically C; it doesn’t use (e.g.) important memory-safety features from C++. (Operator overloading is the only C++-like feature in use.) I suggest that you take advantage of C++ a bit more.
Strictly avoid malloc() in C++. Use std::make_unique(...) or, if there is no other way, a raw new operator. (BTW, there is always another way.) In the latter case, make sure there is a destructor with a delete or delete[]. The use of malloc() in your snippet smells like a memory leak.
What can be const should be const. Initialize as many class members as possible in the constructor’s initializer list and make them const if appropriate. (For example, Matrix dimensions don’t change and should be const.)
When writing a container-like class (which a Matrix may be, in a sense), don’t restrict it to a single data type; your future self will thank you. (What if you need a double instead of a float? Is it going to be a one-liner edit or an all-nighter spent searching where a forgotten float eats away your precision?)
Here’s a quick and dirty runnable example showing matrix multiplication:
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <memory>
namespace matrix {
using std::size_t;
template<typename Element>
class Matrix {
class Accessor {
public:
Accessor(const Matrix& mat, size_t m) : data_(&mat.data_[m * mat.n_]) {}
Element& operator [](size_t n) { return data_[n]; }
const Element& operator [](size_t n) const { return data_[n]; }
private:
Element *const data_;
};
public:
Matrix(size_t m, size_t n) : m_(m), n_(n),
data_(std::make_unique<Element[]>(m * n)) {}
Matrix(Matrix &&rv) : m_(rv.m_), n_(rv.n_), data_(std::move(rv.data_)) {}
Matrix operator *(const Matrix& right) {
Matrix result(m_, right.n_);
for (size_t i = 0; i < m_; ++i)
for (size_t j = 0; j < right.n_; ++j) {
result[i][j] = Element{};
for (size_t k = 0; k < n_; ++k) result[i][j] +=
(*this)[i][k] * right[k][j];
}
return result;
}
Accessor operator [](size_t m) { return Accessor(*this, m); }
const Accessor operator [](size_t m) const { return Accessor(*this, m); }
size_t m() const { return m_; }
size_t n() const { return n_; }
private:
const size_t m_;
const size_t n_;
std::unique_ptr<Element[]> data_;
};
template<typename Element>
std::ostream& operator <<(std::ostream &out, const Matrix<Element> &mat) {
for (size_t i = 0; i < mat.m(); ++i) {
for (size_t j = 0; j < mat.n(); ++j) out << std::setw(4) << mat[i][j];
out << std::endl;
}
return out;
}
} // namespace matrix
int main() {
matrix::Matrix<int> m22{2, 2};
m22[0][0] = 0; // TODO: std::initializer_list
m22[0][1] = 1;
m22[1][0] = 2;
m22[1][1] = 3;
matrix::Matrix<int> m23{2, 3};
m23[0][0] = 0; // TODO: std::initializer_list
m23[0][1] = 1;
m23[0][2] = 2;
m23[1][0] = 3;
m23[1][1] = 4;
m23[1][2] = 5;
matrix::Matrix<int> m32{3, 2};
m32[0][0] = 5; // TODO: std::initializer_list
m32[0][1] = 4;
m32[1][0] = 3;
m32[1][1] = 2;
m32[2][0] = 1;
m32[2][1] = 0;
std::cout << "Original:\n\n";
std::cout << m22 << std::endl << m23 << std::endl << m32 << std::endl;
std::cout << "Multiplied:\n\n";
std::cout << m22 * m22 << std::endl
<< m22 * m23 << std::endl
<< m32 * m22 << std::endl
<< m23 * m32 << std::endl
<< m32 * m23 << std::endl;
}
Possible improvements and other recommendations:
Add consistency checks. throw, for example, a std::invalid_argument when dimensions don’t match on multiplication, i.e. when m_ != right.n_, and a std::range_error when the operator [] gets an out-of-bounds argument. (The checks may be optional, activated (e.g.) for debugging using an if constexpr.)
Use a std::initializer_list or the like for initialization, so that you can have (e.g.) a const Matrix initialized in-line.
Always check your code using valgrind. (Tip: Buliding with -g lets valgrind print also the line numbers where something wrong happened (or where a relevant preceding (de)allocation had happened).)
The code could me made shorter and more elegant (not necessarily more efficient; compiler optimizations are magic nowadays) by not using operator [] everywhere and having some fun with pointer arithmetics instead.
Make the type system better, so that (e.g.) Matrix instances with different types can play well with each other. Perhaps a Matrix<int> multiplied by a Matrix<double> could yield a Matrix<double> etc. One could also support multiplication between a scalar value and a Matrix. Or between a Matrix and a std::array, std::vector etc.

C++ operator overloading fails to output + operation

I'm learning C++ and trying to write a C++ class for matrices, where I store the matrix as a one-dimensional C array. To this end, I defined an element member function to access the matrix elements based on their location in the array. I have then overloaded the << and + operators to handle the display and addition of matrices. The << operator works as intended, as can be demonstrated in the following example:
#include<iostream>
class matrix {
friend std::ostream & operator<<(std::ostream &os, matrix &M);
private:
int rows{}, columns{};
double *array {nullptr};
public:
matrix(int rows, int columns);
~matrix() {}
double & element(int r, int c);
matrix operator+(matrix &M)
{
matrix N(rows, columns);
if (M.rows!=rows || M.columns!=columns){
std::cout << "ERROR: DIMENSIONS OF MATRICES DO NOT MATCH" << std::endl;
}
else{
for (int i{1}; i<=M.rows; i++)
for (int j{1}; j<=M.columns; j++){
N.element(i,j) = element(i,j) + M.element(i,j);
}
}
return N;
}
};
matrix::matrix(int r, int c)
{
rows = r;
columns = c;
array = new double[rows*columns];
for(int i{0}; i<rows*columns; i++) array[i]=0.0;
}
double & matrix::element(int i, int j)
{
int loc{0};
loc = (j-1) + (i-1)*columns;
return array[loc];
}
std::ostream & operator<<(std::ostream &os, matrix &M)
{
for (int i{1}; i<=M.rows; i++){
os << "[ ";
for (int j{1}; j<=M.columns; j++){
os << M.element(i,j) << " ";
}
os << "] \n";
}
return os;
}
int main() {
matrix A(2,2);
matrix B(2,2);
A.element(1,1) = 1;
A.element(1,2) = 2;
A.element(2,1) = 3;
A.element(2,2) = 4;
B.element(1,1) = 1;
B.element(1,2) = 2;
B.element(2,1) = 3;
B.element(2,2) = 4;
std::cout << A << std::endl;
std::cout << B << std::endl;
return 0;
}
I'm then unable to display the addition of two matrices:
std::cout << A+B << std::endl;
If I, however, break up the operation and add the matrices separately before displaying their sum, I get the right output, which makes me believe that the + operator also works correctly:
matrix C(2,2);
C = A+B;
std::cout << C << std::endl;
The error seems to suggest that there may be an issue converting the matrix elements into the ostream, but it's curious that the above workaround solution works.
Your << operator takes a non-const reference to a matrix as parameter. That means it can't take reference to a temporary object.
The result of A+B is a temporary object if you don't assign it to something.
So you need to change this:
std::ostream & operator<<(std::ostream &os, matrix &M);
into this:
std::ostream & operator<<(std::ostream &os, const matrix &M);
You may sooner or later encounter the same problem with your +-operator:
matrix operator+(matrix &M)
should be
// Both `M` and `*this` should be const
matrix operator+(const matrix &M) const
Naturally you will then have a problem with your element method which can only act on a non-const object, so you also need a variant that acts on a const object:
class matrix
{
....
public:
double & element(int r, int c);
double element(int r, int c) const;
...
}
You can't take a non-const reference of a temporary object. You're trying to call operator<< with a temporary (A+B) but the signature of your overloaded operator<< takes a non-const reference so your function isn't a valid candidate.
To fix this you'll need to change a couple things. First, make your overloaded << operator take a const reference to the matrix. And don't forget to fix the friend signature in the class declaration.
std::ostream & operator<<(std::ostream &os, const matrix &M);
Just doing that will still cause errors because the element method is only defined for non-const objects. You'll need to add an overload for element that acts on const matrixes (and that won't let you modify the returned element).
double matrix::element(int i, int j) const
{
int loc = (j-1) + (i-1)*columns;
return array[loc];
}
Your operator<< and operator+ both need to take the input matrix by const reference, so that they can accept temporary matrix objects as input.
Also, operator+ should be const-qualified since it doesn't modify the contents of this. And element() should have a const -qualified overload so it can provide read-only access to a const matrix object.
You are also missing a copy constructor, a copy-assignment operator, a move constructor, and a move-assignment operator, per the Rule of 3/5/0. And also, your destructor is not freeing the C array at all, so it is being leaked.
Try this instead:
#include <iostream>
#include <stdexcept>
#include <utility>
class matrix {
friend std::ostream& operator<<(std::ostream &os, const matrix &M);
private:
int rows{}, columns{};
double* array{nullptr};
public:
matrix(int rows, int columns);
matrix(const matrix &M);
matrix(matrix &&M);
~matrix();
matrix& operator=(matrix M);
double& element(int r, int c);
double element(int r, int c) const;
matrix operator+(const matrix &M) const;
matrix& operator+=(const matrix &M);
};
matrix::matrix(int r, int c)
: rows(r), columns(c)
{
size_t size = rows*columns;
array = new double[size];
for(size_t i = 0; i < size; ++i)
array[i] = 0.0;
}
matrix::matrix(const matrix &M)
: rows(M.rows), columns(M.columns)
{
size_t size = rows*columns;
array = new double[size];
for(size_t i = 0; i < size; ++i)
array[i] = M.array[i];
}
matrix::matrix(matrix &&M)
: rows(M.rows), columns(M.columns), array(M.array)
{
M.rows = M.columns = 0;
M.array = nullptr;
}
matrix::~matrix()
{
delete[] array;
}
matrix& operator=(matrix M)
{
std::swap(rows, M.rows);
std::swap(columns, M.columns);
std::swap(array, M.array);
return *this;
}
double& matrix::element(int r, int c)
{
// TODO: do bounds checking here...
size_t loc = ((r-1)*columns) + (c-1);
return array[loc];
}
double matrix::element(int r, int c) const
{
// TODO: do bounds checking here...
size_t loc = ((r-1)*columns) + (c-1);
return array[loc];
}
std::ostream & operator<<(std::ostream &os, const matrix &M)
{
for (int r = 1; r <= M.rows; ++r){
os << "[ ";
for (int c = 1; c <= M.columns; ++c){
os << M.element(r,c) << " ";
}
os << "]\n";
}
/* alternatively...
size_t loc = 0;
for (int r = 0; r < M.rows; ++r){
os << "[ ";
for (int c = 0; c < M.columns; ++c){
os << M.array[loc++] << " ";
}
os << "]\n";
}
*/
return os;
}
matrix matrix::operator+(const matrix &M) const
{
matrix N(*this);
N += M;
return N;
}
matrix& matrix::operator+=(const matrix &M)
{
if (M.rows != rows || M.columns != columns){
throw std::runtime_error("DIMENSIONS OF MATRICES DO NOT MATCH");
}
for (int r = 1; r <= rows; ++r)
for (int c = 1; c <= columns; ++c){
element(r,c) += M.element(r,c);
}
}
/* alternatively:
size_t size = rows*columns;
for (size_t i = 0; i < size; ++i)
array[i] += M.array[i];
}
*/
return *this;
}
int main() {
matrix A(2,2);
matrix B(2,2);
A.element(1,1) = 1;
A.element(1,2) = 2;
A.element(2,1) = 3;
A.element(2,2) = 4;
B.element(1,1) = 1;
B.element(1,2) = 2;
B.element(2,1) = 3;
B.element(2,2) = 4;
std::cout << A << std::endl;
std::cout << B << std::endl;
return 0;
}

C++ Operator Overload >>

I hadn't found answer even if exist anywhere.
I have class and I want overload >> operator
That code compile but it don't work how I want.
I want put value in all cells inside array, but it only work for 1st cell. Looks like my loop don't work.
Edited:
Full code below. Btw sorry for language but this is my homework and teacher want that names.
#include <cstdlib>
#include <iostream>
#include <string>
#include <cmath>
template <class T>
class Wielomian {
private:
int stopien;
T *wspolczynniki;
public:
friend std::ostream & operator << (std::ostream &output, Wielomian &w)
{
output << "Wielomian: ";
for (int i = w.stopien-1; i >= 0; i--)
{
output << w.wspolczynniki[i] << "x^" << i << " ";
if (i)
output << "+ ";
}
return output;
}
friend std::istream & operator >> (std::istream &input, Wielomian &w)
{
int i = 0;
do {
input >> w.wspolczynniki[i++];
} while (w.stopien < i);
return input;
}
T operator () (T x)
{
T wynik = 0;
for (int i = 0; i < this->stopien; i++)
{
wynik += this->wspolczynniki[i] * pow(x,i);
}
return wynik;
}
T& operator[](const int index)
{
return wspolczynniki[index];
}
Wielomian operator + (const Wielomian &w)
{
const Wielomian *wiekszy;
const Wielomian *mniejszy;
if (w.stopien > this->stopien)
{
wiekszy = &w;
mniejszy = this;
}
else
{
wiekszy = this;
mniejszy = &w;
}
for (int i = 0; i < mniejszy->stopien; i++)
wiekszy->wspolczynniki[i] += mniejszy->wspolczynniki[i];
return *wiekszy;
}
Wielomian operator - (const Wielomian &w)
{
const Wielomian *wiekszy;
const Wielomian *mniejszy;
if (w.stopien > this->stopien)
{
wiekszy = &w;
mniejszy = this;
}
else
{
wiekszy = this;
mniejszy = &w;
}
for (int i = 0; i < mniejszy->stopien; i++)
wiekszy->wspolczynniki[i] -= mniejszy->wspolczynniki[i];
return *wiekszy;
}
Wielomian operator = (const Wielomian &w)
{
this->stopien = w.stopien;
this->wspolczynniki = new float[this->stopien];
memcpy(this->wspolczynniki, w.wspolczynniki, w.stopien * sizeof(double));
}
Wielomian(const Wielomian &w)
{
this->stopien = w.stopien;
this->wspolczynniki = new float[this->stopien];
memcpy(this->wspolczynniki, w.wspolczynniki, w.stopien * sizeof(double));
}
Wielomian(int stopien = 0, T wspolczynik[] = { 3 })
{
this->stopien = stopien;
wspolczynniki = new T[this->stopien];
for (int i = 0; i < stopien; i++)
{
this->wspolczynniki[i] = wspolczynik[i];
}
}
~Wielomian()
{
free(this->wspolczynniki);
}
};
int main()
{
double tab[4] = {3,4,5,6};
Wielomian<double> w1(4,tab);
std::cin >> w1;
std::cout << w1;
std::cin.get();
std::cin.get();
return 0;
}
Your while condition in operator >> is wrong. In your code you have:
int i = 0;
do {
input >> w.wspolczynniki[i++];
} while (w.stopien < i);
i is 0 at the beginning, and then after input >> w.wspolczynniki[i++] it is 1. The while condition is (w.stopien < i) so if w.stopien (which is 4 in your example) is smaler then i which is 1 in the first iteration, you will continue the loop. But 4 < 1 is false you will always only read one value.
So get your do-while to work you would need to change it to (w.stopien > i). But as you test if your index i is in the correct range you shouldn't use a do-while at all, but a while loop.
int i = 0;
while (i < w.stopien) {
input >> w.wspolczynniki[i++];
}
Or even a for loop, which would make clearer what you are doing:
for(int i=0; i< w.stopien; i++) {
input >> w.wspolczynniki[i];
}
In addition to that - and what is already mentioned in the comments - never combine the memory allocations and deallocation that don't belong together. If you use new[] then you have to use delete[] to free the memory and not free.
And don't use signed numbers (int) for indices, so stopien and i should be unsigned (e.g. size_t). And for stopien you should ensure on construction that it is 1 or larger.
And if you are allowed to you should switch form T* wspolczynniki to std::vector<T> wspolczynniki that would allow you to get rid of the copy constructor, the assignment operator, the destructor, you would not need int stopien, and you could simplify other parts of the code using [algorithm](https://en.cppreference.com/w/cpp/algorithm), or at least keep that you normally would use astd::vector` (or other containers) then doing the allocation and the copying yourself.

C++ Matrix Operator+

The method template <class T> const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const for program matrix.cc should be able to return the sum of calling object's matrix and rhs's matrix as a new object. Also, the lhs and rhs rows and cols will be equal.
The error output that I am receiving from the compiler is:
[hw7] make clean && make bin/test_add && ./bin/test_add UserSettings ✱
rm -f bin/*
g++ -std=c++11 -Wall -I inc -I src -c src/test_matrix_add.cc -o bin/test_matrix_add.o
g++ -std=c++11 -Wall -I inc -I src -o bin/test_add bin/test_matrix_add.o
Testing Matrix::operator+
Expected Matrix2[0][0]: 3.0, Actual: 1
FAILED
Could someone let me know why I receive this "Failed" output when I know I pass the // TEST MUL ASSIGMENT OP CORRECT RETURN section.
Here is my matrix.cc:
#include <matrix.h>
template <class T>
Matrix<T>::Matrix() {
rows_ = 0;
cols_ = 0;
m_ = nullptr;
}
template <class T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
: rows_(rows), cols_(cols) {
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
}
}
template <class T>
Matrix<T>::Matrix(const Matrix<T> &that) {
rows_ = that.rows_;
cols_ = that.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = that.m_[i][j];
}
}
}
template <class T>
Matrix<T>::~Matrix() {
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i]; // delete columns
}
delete[] m_; // delete columns
}
template <class T>
T Matrix<T>::Get(unsigned int row, unsigned int col) const {
if (row > rows_ && col > cols_) {
throw std::out_of_range("error: index out of range");
}
return this->m_[row][col];
}
template <class T>
const Matrix<T> &Matrix<T>::operator=(const Matrix<T> &rhs) {
if (this == &rhs) {
return *this;
} // returns the address
for (unsigned int i = 0; i < rows_; ++i) {
delete[] m_[i];
}
delete[] m_;
rows_ = rhs.rows_;
cols_ = rhs.cols_;
m_ = new T *[rows_];
for (unsigned int i = 0; i < rows_; ++i) {
m_[i] = new T[cols_];
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] = rhs.m_[i][j];
}
}
return *this;
}
template <class T>
const Matrix<T> &Matrix<T>::operator*=(T rhs) {
for (unsigned int i = 0; i < rows_; ++i) {
for (unsigned int j = 0; j < cols_; ++j) {
m_[i][j] *= rhs;
}
}
return *this;
}
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const {
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_)) {
std::cout << "Cannont add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
for (unsigned int i = 0; i < lhs.rows_; ++i) {
for (unsigned int j = 0; j < lhs.cols_; ++j) {
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Here is my matrix.h:
#include <cassert>
// using assert
#include <exception>
#include <iostream>
template <class T>
class Matrix {
public:
friend class MatrixTester;
Matrix(); // for testing, useless in practice
Matrix(unsigned int rows, unsigned int cols);
Matrix(const Matrix<T> &that);
~Matrix();
T Get(unsigned int row, unsigned int col) const;
const Matrix<T> &operator=(const Matrix<T> &rhs);
const Matrix<T> &operator*=(T rhs);
const Matrix<T> operator+(const Matrix<T> &rhs) const;
private:
T **m_;
unsigned int rows_;
unsigned int cols_;
};
#include <matrix.cc> //NOLINT
This is my test_matrix_add.cc tester:
#include <test_matrix.h>
int main(int argc, char** argv) {
MatrixTester tester;
cout << "Testing Matrix::operator+" << endl;
if (tester.Test_AddOp()) {
cout << " PASSED" << endl;
return 0;
}
cout << " FAILED" << endl;
return 1;
}
bool MatrixTester::Test_AddOp() const {
const int kRows = 4, kCols = 5;
Matrix<double> m1;
m1.m_ = new double*[kRows];
for (unsigned int i = 0; i < kRows; ++i) {
m1.m_[i] = new double[kCols];
for (unsigned int j = 0; j < kCols; ++j)
m1.m_[i][j] = (i + 1.0) * (j + 1.0);
}
m1.rows_ = kRows;
m1.cols_ = kCols;
// TEST ADDITION CORRECTNESS
Matrix<double> m2;
m2 = m1;
// + m1 + m1;
if (m2.m_[0][0] != 3) {
cout << " Expected Matrix2[0][0]: 3.0, Actual: " << m2.m_[0][0] << endl;
return false;
}
if (m2.m_[1][3] != 24.0) {
cout << " Expected Matrix2[1][3]: 24.0, Actual: " << m2.m_[1][3] << endl;
return false;
}
if (m2.m_[2][2] != 27.0) {
cout << " Expected Matrix2[2][2]: 27.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
if (m2.m_[3][4] != 60.0) {
cout << " Expected Matrix2[2][2]: 60.0, Actual: " << m2.m_[2][2] << endl;
return false;
}
return true;
}
Firstly, there is way too much code here.
To address your problem, I see don't see you allocating memory to lhs.m_. This is a problem because you initialize lhs with the default constructor, which only assigns this->m_ to a nullptr.
To fix this, this should work (although untested):
template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) const
{
if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
Matrix<T> lhs;
lhs.rows_ = this->rows_;
lhs.cols_ = this->cols_;
// Allocate memory for `lhs.m_`, like you did in your 2nd constructor
lhs.m_ = new T* [rows_];
for (unsigned i = 0; i < rows_; ++i)
{
m_[i] = new T[cols_];
}
// [End] allocation
for (unsigned int i = 0; i < lhs.rows_; ++i)
{
for (unsigned int j = 0; j < lhs.cols_; ++j)
{
lhs[i][j] += rhs[i][j];
}
}
return lhs;
}
Also, somewhat unrelated, be careful that you consistently treat m_ as a double-pointer. I didn't read all your code, but just be cautious. And also remember that you have to deallocate all the memory you allocated with new in your destructor. Personally, I believe you should use smart pointers from <memory> (e.g. std::unique_ptr, etc), which you can learn more about here. Using smart pointers would make the pointers deallocate the memory on their own and you wouldn't have to worry about memory leaks.
Edit 1
As walnut stated, a better solution would be to just call the 2nd constructor, which will allocate the memory for you. So, your revised function would be:
template <class T>
/**
Note:
> When you call this function (e.g. Matrix<T> new_mat = mat1 + mat2),
`mat1` is `this` and `mat2` is what you're calling `rhs`. I've done
some renaming and corrected your logic errors here
*/
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& other) const
{
if (!(this->cols_ == other.cols_) || (this->rows_ == other.rows_))
{
std::cout << "Cannot add matrices. Wrong dimensions\n";
exit(0);
}
// Call the 2nd constructor
Matrix<T> res(this->rows_, this->cols_);
for (unsigned i = 0; i < res.rows_; ++i)
{
for (unsigned j = 0; j < res.cols_; ++j)
{
res.m_[i][j] = this->m_[i][j] + other.m_[i][j];
}
}
return res;
}
Edit 2
The above code has been correct to add the matrices correctly, as per #walnut's comment.

c++ debug '<<' no operator found

I am trying to run the following code on c++ but keep geting error. Can anyone solve it for me please.
the error message from c++ says:
Error 6 error C2679: binary '<<' : no operator found which takes a
right-hand operand of type 'MVector'
#include <iostream>
#include <cmath>
#ifndef MVECTOR_H // the 'include guard'
#define MVECTOR_H // see C++ Primer Sec. 2.9.2
#include <vector>
#include <string>
#include <fstream>
class MVector
{
public:
// constructors
MVector() {}
explicit MVector(int n) : v(n) {}
MVector(int n, double x) : v(n, x) {}
void push_back(double x)
{
v.push_back(x);
}
double AV()
{
double sum = 0.0, average = 0.0;
for (double i = 0; i<v.size(); i++)
{
sum += v[i];
}
average = sum / v.size();
return average;
}
MVector RunningAverage(int m, int p)
{
MVector movingaverage(v.size() - m - p - 1);
for (int i = m; i < v.size() - p; i++)
{
double sum = 0.0;
if ((i + p < v.size()))
{
for (int j = i - m; j <= i + p; j++)
{
sum += v[j];
movingaverage[i - m] = sum / (m + p + 1);
}
}
}
return movingaverage; // Edit by jpo38
}
// access element (lvalue)
double &operator[](int index) { return v[index]; }
// access element (rvalue)
double operator[](int index) const { return v[index]; }
int size() const { return v.size(); } // number of elements
private:
std::vector<double> v;
};
#endif
int main()
{
using namespace std;
// create an MVector
MVector x;
// add elements to the vector
x.push_back(1.3);
x.push_back(3.5);
x.push_back(3.0);
x.push_back(2.0);
// x now contains 1.3 and 3.5
// print x
std::cout << " x:= ( ";
for (int i = 0; i < x.size(); i++)
std::cout << x[i] << " ";
std::cout << ")\n";
std::cout << x.RunningAverage(0, 1.0) << endl;
return 0;
}
x.RunningAverage(0, 1.0) returns a MVector that cannot be sent to std::cout, unless you declare the operator<< taking a MVector as parameter.
Alternatively, you can replace:
std::cout << x.RunningAverage(0, 1.0) << endl;
By:
MVector av = x.RunningAverage(0, 1.0);
for (int i = 0; i < av.size(); i++)
std::cout << av[i] << " ";
Or, declare the operator:
std::ostream& operator<<(std::ostream& out,const MVector& b)
{
for (int i = 0; i < b.size(); i++)
out << b[i] << " ";
return out;
}
And then std::cout << x.RunningAverage(0, 1.0) << std::endl; will work.
And you can then also replace, in your main function:
for (int i = 0; i < x.size(); i++)
std::cout << x[i] << " ";
By:
std::cout << x;
Live demo: http://cpp.sh/7afyi
You haven't overloaded operator<< for MVector.
You can do that with:
std::ostream& operator<<(std::ostream& output, MVector const& vec)
{
// use "output << …;" to do printing
return output;
}