C++, overload * for matrix multiplication - c++

I'm having a great deal of trouble trying to overload the multiplication operator * for matrix multiplication. I've defined a matrix class
#ifndef MMATRIX_H
#define MMATRIX_H
#include <vector>
#include <cmath>
// Class that represents a mathematical matrix
class MMatrix
{
public:
// constructors
MMatrix() : nRows(0), nCols(0) {}
MMatrix(int n, int m, double x = 0) : nRows(n), nCols(m), A(n * m, x)
{}
// set all matrix entries equal to a double
MMatrix &operator=(double x)
{
for (int i = 0; i < nRows * nCols; i++)
A[i] = x;
return *this;
}
// access element, indexed by (row, column) [rvalue]
double operator()(int i, int j) const
{
return A[j + i * nCols];
}
// access element, indexed by (row, column) [lvalue]
double &operator()(int i, int j)
{
return A[j + i * nCols];
}
// size of matrix
int Rows() const { return nRows; }
int Cols() const { return nCols; }
// operator overload for matrix * vector. Definition (prototype) of member class
MVector operator*(const MMatrix& A);
private:
unsigned int nRows, nCols;
std::vector<double> A;
};
#endif
And here is my attempted operator overload
inline MMatrix operator*(const MMatrix& A, const MMatrix& B)
{
MMatrix m(A), c(m.Rows(),m.Cols(),0.0);
for (int i=0; i<m.Rows(); i++)
{
for (int j=0; j<m.Cols(); j++)
{
for (int k=0; k<m.Cols(); k++)
{
c(i,j)+=m(i,k)*B(k,j);
}
}
}
return c;
}
I'm sure that there is nothing wrong with the actual multiplication of elements.
The error that I get is from my main .cpp file where I have tried to multiply two matrices together C=A*B; and I get this error,
error: no match for 'operator=' (operand types are 'MMatrix' and 'MVector')

There are 2 ways to overload operator*:
MMatrix MMatrix::operator*(MMatrix); //or const& or whatever you like
MMatrix operator*(MMatrix, MMatrix);
These are both valid, but different with slightly different semantics.
For your definition to match your declaration change the definition to:
MMatrix MMatrix::operator*(const MMatrix & A)
{
//The two matrices to multiple are (*this) and A
MMatrix c(Rows(),A.Cols(),0.0);
for (int i=0; i < Rows(); i++)
{
for (int j=0; j < A.Cols(); j++)
{
for (int k=0; k < Cols(); k++)
{
c(i,j) += (*this)(i,k)*A(k,j);
}
}
}
return c;
}
As for the error you're seeing, it seems in your class you declared the operator to take a matrix and return a vector. You probably meant to return a matrix instead. The error is telling you that you can't assign a MVector to a MMatrix.

I believe, you need to define copy constructor and copy assignment:
MMatrix(const MMatrix& other);
MMatrix& operator=(const MMatrix& other);
Move constructor and assignment wouldn't heart either:
MMatrix(MMatrix&& other);
MMatrix& operator=(MMatrix&& other);
Same goes to your MVector.

Related

constructor\destructor or understanding of OOP

Im trying to to use operator overloading with both + and = operator on a matrix class which i created. either the constructor or destructor is causing a problem or it isn't either (though i grayed out each of them and both and the code seems to work). could someone please help me understand what is causing this strange behavior. when i try to create 3 matrixes a b and c then try a = b+c; it just fails.
header file
#ifndef MATRIX_H;
#define MATRIX_H;
using namespace std;
enter code here
class matrix
{
friend ostream& operator<< (ostream&, matrix &);
public:
matrix();
matrix(int,int); //constructor
matrix(const matrix&);//copy constructor
~matrix();
int getRow();
int getCol();
void setRow(int);
void setCol(int);
class arr1D{ //proxy class to allow the use of [][] operator
public:
arr1D(int* a):temp(a){}
int &operator[](int a){
return temp[a];
}
int *temp;
};
arr1D operator[](int a){
return arr1D(arr2[a]);
}
matrix& operator=(const matrix& );
matrix& operator+(const matrix& );
protected:
private:
int row , col;
int **arr2;
};
#endif // MATRIX_H
enter code here
cpp file
#include <iostream>
#include "matrix.h"
using namespace std;
matrix::matrix()
{
setCol(0);
setRow(0);
**arr2=0;
}
matrix::matrix(int x, int y) //matrix constructor creates x*y matrix and initializes to 0's
{
setCol(y);
setRow(x);
arr2 = new int * [getRow()];
if (arr2) {
for (int i = 0; i < getRow(); i++) {
arr2[i] = new int [getCol()];
};
};
for (int i=0; i<getRow();i++){
for (int j=0;j<getCol();j++){
arr2[i][j]=0;
};
};
}
matrix::matrix(const matrix &m){ //defines the copying constructor
row=m.row;
col=m.col;
arr2 = new int*[row];
for (int i=0; i<row; i++){
arr2[i] = new int[col];
}
for (int i=0; i<row; i++){
for (int j=0; j<col; j++){
arr2[i][j] = m.arr2[i][j];
}
}
}
matrix::~matrix(){ //defines the destructor
for (int i=0; i<row; i++){
delete[] arr2[i];
}
delete[] arr2;
}
int matrix::getRow(){ //getter for row
return row;
}
int matrix::getCol(){ // getter for col
return col;
}
void matrix::setRow(int x){ //setter for row
row=x;
}
void matrix::setCol(int x){ //setter for col
col=x;
}
ostream& operator<< (ostream& output, matrix& a){
int i,j;
for (i=0; i < a.getRow() ; i++){
for (j=0; j< a.getCol() ; j++){
output << " " <<a.arr2[i][j];
};
output << "\n";
};
return output;
}
matrix& matrix::operator=(const matrix& right)
{
if (this == &right) { // Same object?
return *this;
}
row = right.row;
col = right.col;
for (int i=0; i<row; i++)
{
for (int j=0; j<col; j++){
arr2[i][j]=right.arr2[i][j];
}
}
return *this ;
}
matrix& matrix::operator+(const matrix& right)
{
int row=right.row;
int col=right.col;
matrix result(row,col);
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
//cout<<"arr2[i][j]="<<arr2[i][j]<<endl;
//cout<<"right.arr2[i][j]="<<right.arr2[i][j]<<endl;
result.arr2[i][j]=(arr2[i][j] + right.arr2[i][j]);
//cout<<"result.arr2[i][j]="<<result.arr2[i][j]<<endl;
};
};
return result;
}
First, as the other answer pointed out, you are returning a reference to a temporary in your operator +. That is undefined behavior.
But instead of writing operator + in this fashion, what you should do is write operator += instead, and then in turn, write operator + in terms of operator +=. Since a programmer would expect += to also work for the matrix in addition to +, it makes no sense to leave out +=.
For operator +=, you would in this case return a reference to the current object.
So all we need to do is move the code in operator + to operator +=:
#include <exception>
//...
matrix& matrix::operator+=(const matrix& right)
{
if(row != right.row || col != right.col)
throw std::logic_error("Matrix not the same size");
for (int i = 0; i < right.row; i++)
{
for (int j = 0; j < right.col; j++)
arr2[i][j] += right.arr2[i][j]);
}
return *this;
}
Note that we return a reference to the current matrix, since += modifies the current matrix. Also note that we throw an exception on an illegal matrix being sent to +=. This IMO makes more sense than returning a legitimate matrix back on error. If the matrix is not the same size, the code should not try and return a matrix back.
Now operator + can be written in terms of +=:
matrix matrix::operator+(const matrix& right)
{
return matrix(*this) += right;
}
Believe it or not, that's it. All we did was create a temporary matrix and call += with the passed in argument. We return the result of this as a brand new matrix, just as we expect.
The other issue is the assignment operator. Given that you've written a copy constructor and destructor, and the copy constructor works without having to use the assignment operator, then the copy / swap idiom can be used to implement the assignment operator.
#include <algorithm>
//...
matrix& matrix::operator=(const matrix& right)
{
matrix temp(right);
std::swap(temp.arr2, arr2);
std::swap(temp.row, row);
std::swap(temp.col. col);
return *this;
}
All we did here was create a temporary matrix of the passed in object and swap out its contents with the current object's contents. When the temporary dies off at the return, the temporary destroys the old contents that were swapped out.
This method has the advantage of not only being very simple to implement (just a bunch of calls to std::swap), it is also exception safe. If there is an issue creating the temporary matrix, a std::bad_alloc exception would have been thrown, without messing up or altering any members of this. The issue with the other answer given, where you're deallocating the memory first before allocating the new memory, is solved by using the above technique.

Destructor not called and issue with program exiting abnormally

I have the following code for defining a class Matrix. The definitions in the header file are as follows:
#ifndef MATRIX_H
#define MATRIX_H
/* General matrix class */
class Matrix
{
public:
Matrix(int m, int n, double ini);
virtual ~Matrix();
Matrix(const Matrix& other); //copy ctor
Matrix& operator=(const Matrix& other); //assignment operator;
double operator()(int i, int j) const; //access element in the matrix
double& operator() (int i, int j); //set element in the matrix
friend Matrix operator+(const Matrix& mat1, const Matrix& mat2); //Matrix addition
friend Matrix operator+(const Matrix& mat1, double a); //scaler multiplication
int dimension() const {return rows*cols;} //getter method for dimension
protected:
private:
int rows; //number of rows in the matrix
int cols; //number of cols in the matrix
double* d; //pointer to the representation of the matrix
};
The implementation of the parts relevant to the question are shown below.
#include "Matrix.h"
#include<iostream>
Matrix::Matrix(int m, int n, double ini):rows{m},cols{n},d{new double[m*n]}
{
//ctor
double* p = d;
for(int i=0;i<rows*cols;i++)
{
*p++ = ini;
}
}
Matrix::~Matrix()
{
//dtor
delete []d;
}
Matrix& Matrix::operator=(const Matrix& rhs)
{
if (this == &rhs) return *this; // handle self assignment
if (rows*cols<=rhs.rows*rhs.cols)
{
delete []d;
d = new double[rhs.rows*rhs.cols];
rows = rhs.rows;
cols = rhs.cols;
for(int i=0;i<rows*cols;i++)
{
d[i] = rhs.d[i];
}
}
//assignment operator
return *this;
}
double Matrix::operator()(int i, int j) const
{
return d[rows*i + j];
}
double& Matrix::operator()(int i, int j)
{
return d[rows*i+j];
}
Now, I have a simple test application that creates a matrix, assigns values to the elements in the matrix, as well reads the value of an element (given a row and a column number).
#include <iostream>
#include "Matrix.h"
using namespace std;
int main()
{
int i,j;
Matrix A(3,2,0.0);
cout<<A.dimension()<<endl;
// assign values to matrix elements
for (i=0;i<3;i++)
{
for (j=0;j<2;j++) A(i,j) = 0.1*i*j;
}
// access matrix elements
double sum = 0.0;
for (i=0;i<3;i++) {
for (j=0;j<2;j++) sum += A(i,j); }
cout << "The sum of the matrix elements is ";
cout << sum << endl;
return 0;
}
My issue is that while everything compiles without problems, when run, the main function freezes -- the "sum" above is computed though. Was wondering if this is due to the destructor not being called or being unable to be called. Much appreciated if anyone has any ideas.
I think your code are wrong in operator()
double Matrix::operator()(int i, int j) const
{
return d[cols*i + j];
}
double& Matrix::operator()(int i, int j)
{
return d[cols*i+j];
}
And you overflow the array d[]

How to correctly overload + operator

I am trying to define a simple class to work with 2d matrices, called Matrix2D01, and having trouble with the + operator.
I have the += operator which is working fine,
Matrix2D01& Matrix2D01::operator+=(Matrix2D01& mat2) {
int i,j;
for (i=0;i<M;i++)
for (j=0;j<N;j++) mat[i][j]+=mat2[i][j];
return *this;
}
The + operator is defined:
Matrix2D01 Matrix2D01::operator+(Matrix2D01& mat2) {
Matrix2D01 result(1,1);
result=*this;
result+=mat2;
return result;
}
When i try to use the + operator, for example by
mat3=mat1+mat2;
the compiler gives an error:
../MatrixGames.cpp:17:12: error: no match for ‘operator=’ in ‘mat3 = Matrix2D01::operator+(Matrix2D01&)((* & mat2))’
If anyone can tell me what I'm doing wrong it will be greatly appreciated.
Thanks.
I also have a = operator defined,
Matrix2D01& Matrix2D01::operator=(Matrix2D01& mat2) {
if (this==&mat2) return *this;
int i,j;
for (i=0;i<M;i++) {
delete [] mat[i];
}
delete [] mat;
M=mat2.Dimensions()[0];
N=mat2.Dimensions()[1];
mat = new double* [M];
for (i=0;i<M;i++) {
mat[i]=new double [N];
}
for (i=0;i<M;i++)
for (j=0;j<M;j++)
mat[i][j]=mat2[i][j];
return *this;
}
here is a complete test case:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
using namespace std;
class Matrix2D01 {
protected:
int D;
double **mat;
int M,N;
public:
Matrix2D01(int m,int n);
Matrix2D01(int m,int n,double d);
~Matrix2D01();
vector <int> Dimensions() {vector <int> d(D,M); d[1]=N; return d;}
double* operator[](int i) {return mat[i];}
Matrix2D01& operator=(Matrix2D01& mat2);
Matrix2D01& operator+=(Matrix2D01& mat2);
Matrix2D01 operator+(Matrix2D01& mat2);
};
Matrix2D01::Matrix2D01(int m, int n) {
int i,j;
D=2;
M=m;
N=n;
mat = new double* [M];
for (i=0;i<M;i++) {
mat[i]=new double [N];
}
for (i=0;i<M;i++)
for (j=0;j<M;j++)
mat[i][j]=0;
}
Matrix2D01::Matrix2D01(int m, int n,double d) {
int i,j;
D=2;
M=m;
N=n;
mat = new double* [M];
for (i=0;i<M;i++) {
mat[i]=new double [N];
}
for (i=0;i<M;i++)
for (j=0;j<M;j++)
mat[i][j]=d;
}
Matrix2D01::~Matrix2D01() {
int i;
for (i=0;i<M;i++) {
delete [] mat[i];
}
delete [] mat;
}
Matrix2D01& Matrix2D01::operator=(Matrix2D01& mat2) {
if (this==&mat2) return *this;
int i,j;
for (i=0;i<M;i++) {
delete [] mat[i];
}
delete [] mat;
M=mat2.Dimensions()[0];
N=mat2.Dimensions()[1];
mat = new double* [M];
for (i=0;i<M;i++) {
mat[i]=new double [N];
}
for (i=0;i<M;i++)
for (j=0;j<M;j++)
mat[i][j]=mat2[i][j];
return *this;
}
Matrix2D01& Matrix2D01::operator+=(Matrix2D01& mat2) {
int i,j,M2,N2;
M2=mat2.Dimensions()[0];
N2=mat2.Dimensions()[1];
if ((M!=M2)||(N!=N2)) {
cout<<"error: attempted to add non-matching matrices";
return *this;
}
for (i=0;i<M;i++)
for (j=0;j<N;j++) mat[i][j]+=mat2[i][j];
return *this;
}
Matrix2D01 Matrix2D01::operator+(Matrix2D01& mat2) {
Matrix2D01 result(1,1);
result=*this;
result+=mat2;
return result;
}
int main() {
Matrix2D01 mat1(2,2,1);
Matrix2D01 mat2(2,2,2);
Matrix2D01 mat3(2,2,4);
mat3+=mat1;
mat3=mat1+mat2;
return 1;
}
Herb Sutter advocates the following canonical way to overload operator + (please read GotW, it is really well written and interesting):
Don't include operator + as a member function, instead make it a free function.
Pass one object by value and the other by const reference. This makes it possible to use move operators when you add to a temporary.
Implement in terms of operator +=:
Matrix2D01 operator+(Matrix2D01 a, const Matrix2D01 &b)
{
a += b;
return a;
}
I've posted the code of the Matrix class I had written for an assignment on Discrete Mathematics last Sem
Notice how the assignment operator and the copy constructor are implemented All you need to do is write an assignment operator (I'd recommend that you write a copy constructor as well)
#pragma once
#include <vector>
#include <istream>
#include <ostream>
class Matrix
{
private:
unsigned int rows, cols;
std::vector<std::vector<int> > matrix;
public:
// Creates a Matrix with the given dimensions and sets the default value of all the elements to 0
Matrix(unsigned int rows, unsigned int cols);
// Destructor
~Matrix();
// Converts the relation set into it's adjacency Matrix representation
static Matrix CreateFromRelationSet( std::vector<std::pair<int, int> > relationSet);
// Copy Constructor
Matrix(const Matrix& cSource);
// Assignment Operator
Matrix& operator=(const Matrix& cSource);
// Resets all the elements of the matrix to 0
void Reset();
// Resizes the matrix to the given size
void Resize(unsigned int rows, unsigned int cols);
// Returns the number of rows
unsigned int getRows();
// Returns the number of columns
unsigned int getCols();
// Returns the smallest element from the matrix
int getSmallestElement();
// Returns the greatest element from the matrix
int getGreatestElement();
// Returns true if element is found and sets the row and column
// Returns false if not found
bool getPosition(int element, int* i, int* j);
// Deletes a row from the Matrix
void DeleteRow(unsigned int row);
// Deletes a column from the Matrix
void DeleteColumn(unsigned int col);
// Returns the element at (i,j)
int& operator()(unsigned int i, unsigned j);
// Returns the element at (i,j). Use the () operators instead
int getElementAt(unsigned int i, unsigned j);
friend std::ostream& operator << (std::ostream& out, Matrix& m);
friend std::istream& operator >> (std::istream& in, Matrix& m);
Matrix operator + (Matrix M);
Matrix operator - (Matrix M);
Matrix operator * (Matrix M);
};
// For use with cin & cout
std::ostream& operator << (std::ostream& out, Matrix& m);
std::istream& operator >> (std::istream& in, Matrix& m);
#include "Matrix.h"
Matrix::Matrix(unsigned int rows, unsigned int cols)
{
this->rows = rows;
this->cols = cols;
matrix.resize(rows);
for(std::vector<int>& i: matrix)
i.resize(cols);
Reset();
}
Matrix::~Matrix()
{
}
// local helper function
int findMaxFromSet(std::vector<std::pair<int, int> > set)
{
int maxVal = 0;
for(unsigned int i = 0; i < set.size(); i ++)
{
int p = set[i].first > set[i].second ? set[i].first : set[i].second;
maxVal = maxVal > p ? maxVal : p;
}
return maxVal;
}
Matrix Matrix::CreateFromRelationSet (std::vector<std::pair<int, int> > relationSet)
{
int max = findMaxFromSet(relationSet);
Matrix M(max,max);
M.Reset();
for(auto i = relationSet.begin(); i != relationSet.end(); ++ i)
M(i->first - 1, i->second - 1) = 1;
return M;
}
void Matrix::Reset()
{
for (auto& i: matrix)
for(auto& j: i)
j = 0;
}
void Matrix::Resize(unsigned int rows, unsigned int cols)
{
matrix.resize(rows);
for(auto& i:matrix)
i.resize(cols);
}
unsigned int Matrix::getRows()
{
return rows;
}
unsigned int Matrix::getCols()
{
return cols;
}
Matrix::Matrix(const Matrix& cSource)
{
rows = cSource.rows;
cols = cSource.cols;
matrix = cSource.matrix;
}
bool Matrix::getPosition(int element, int* i, int* j)
{
for(unsigned int ii = 0; ii < getRows(); ii ++)
for(unsigned int jj = 0; jj < getCols(); jj ++)
if(matrix[ii][jj] == element)
{
*i = ii;
*j = jj;
return true;
}
return false;
}
Matrix& Matrix::operator=(const Matrix& cSource)
{
// check for self-assignment
if (this == &cSource)
return *this;
if(this->getRows() < cSource.rows)
{
this->rows = cSource.rows;
this->matrix.resize(cSource.rows);
}
if(this->getCols() < cSource.cols)
{
this->cols = cSource.cols;
for(auto& i:this->matrix)
i.resize(cSource.cols);
}
for(unsigned int i = 0; i < rows; i++)
for(unsigned int j = 0; j < cols; j++)
this->matrix[i][j] = const_cast<Matrix&>(cSource)(i,j);
return *this;
}
std::ostream& operator << (std::ostream& out, Matrix& m)
{
for(auto& i: m.matrix)
{
for(auto& j: i)
out<<j<<'\t';
out<<std::endl;
}
return out;
}
std::istream& operator >> (std::istream& in, Matrix& m)
{
for(auto& i: m.matrix)
for(auto& j: i)
in>>j;
return in;
}
Matrix Matrix::operator + (Matrix op)
{
// Find the rows and cols of the new matrix
unsigned int r = this->getRows() > op.getRows()?this->getRows():op.getRows();
unsigned int c = this->getCols() > op.getCols()?this->getCols():op.getCols();
// Create Matrices
Matrix A = *this;
Matrix B = op;
Matrix R(r,c);
// Assign values
for(unsigned int i = 0; i < A.rows; i++)
for(unsigned int j = 0; j < A.cols; j++)
R(i,j) = A(i,j) + B(i,j);
return R;
}
Matrix Matrix::operator - (Matrix op)
{
// Find the rows and cols of the new matrix
unsigned int r = this->getRows() > op.getRows()?this->getRows():op.getRows();
unsigned int c = this->getCols() > op.getCols()?this->getCols():op.getCols();
// Create Matrices
Matrix A = *this;
Matrix B = op;
Matrix R(r,c);
// Assign values
for(unsigned int i = 0; i < A.rows; i++)
for(unsigned int j = 0; j < A.cols; j++)
R(i,j) = A(i,j) - B(i,j);
return R;
}
Matrix Matrix::operator* (Matrix op)
{
Matrix A = *this;
Matrix B = op;
if(A.getCols() != B.getRows())
throw std::exception("Matrices cannot be multiplied");
Matrix M(A.getRows(), B.getCols());
for(unsigned int i=0 ; i<A.getRows() ; i++)
for(unsigned int j=0 ; j<B.getCols() ; j++)
for(unsigned int k=0 ; k<B.getRows() ; k++)
M(i,j) = M(i,j) + A(i,k) * B(k,j);
return M;
}
int& Matrix::operator()(unsigned int i, unsigned j)
{
return matrix[i][j];
}
int Matrix::getElementAt(unsigned int i, unsigned j)
{
return (*this)(i,j);
}
int Matrix::getSmallestElement()
{
int result = matrix[0][0];
for(auto i:matrix)
for(auto j : i)
if(j < result)
result = j;
return result;
}
int Matrix::getGreatestElement()
{
int result = matrix[0][0];
for(auto i:matrix)
for(auto j : i)
if(j > result)
result = j;
return result;
}
void Matrix::DeleteRow(unsigned int row)
{
matrix.erase(matrix.begin() + row);
rows --;
}
void Matrix::DeleteColumn(unsigned int col)
{
for(auto& i: matrix)
i.erase(i.begin() + col);
cols --;
}
UPDATE:
result=*this;
In your code you are trying to allocate result the value of *this using the assignment operator, but no assignment operator is defined and the compiler doesn't find a match
Writing an assignment operator overload will solve this issue.
And if you have a copy constructor you can do something like:
Matrix2D01 Matrix2D01::operator+(Matrix2D01& mat2) {
Matrix2D01 result = *this;
result+=mat2;
return result;
}
Writing Assignment Operators: http://www.learncpp.com/cpp-tutorial/912-shallow-vs-deep-copying/
And if you're interested in the details - here you go: http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html
Your operands should be const references. Otherwise, you
can't use a temporary to initialize them. (In this case, the
return value of operator+ is a temporary, and thus, cannot be
bound to the non-const reference of operator=.)
If your operator+ is a member, it should be const as well.
After all, it doesn't modify the object it is called on. So:
Matrix2D01& Matrix2D01::operator=( Matrix2D01 const& mat2 );
Matrix2D01& Matrix2D01::operator+=( Matrix2D01 const& mat2 );
Matrix2D01 Matrix2D01::operator+( Matrix2D01 const& mat2 ) const;
Also, your assignment operator is broken. (Think of what will
happen, if one of the allocations fails after you've freed the
original data.) In general, if you have to test for self
assignment, the assignment operator is broken.

'Invalid use of void expression' passing arguments of functions

This is a piece of my code that solves systems of differential equations.
Vector dydx(Neq);
void DiffEq(Vector x, Vector &dydx)
{
dydx(0) = x(1);
dydx(1) = -x(0);
}
double MidPoint(int n, Vector x)
{
double h=H/n;
Matrix z(n+1,n+1);
z.fillRow(0,x);
DiffEq(x, dydx);
z.fillRow(1,AddVec(x, dydx*h)); //Error: Invalid use of void expression
for (int j=1; j<n; j++)
{
DiffEq(z.getRow(j), dydx);
z.fillRow(j+1, AddVec(z.getRow(j-1), dydx*h*2)); //error: void value not ignored as it ought to be
}
DiffEq(z.getRow(n), dydx);
return 0.5*AddVec(z.getRow(n), z.getRow(n-1), dydx*h); //Error: Invalid use of void expression
}
The classes Vector and Matrix are custom. This is Vector
class Vector
{
public:
Vector(size_t size): vSize(size), vData(size){}
int getSize(){return vSize;}
double& operator()(size_t i){return vData[i];}
double operator()(size_t i) const {return vData[i];}
void operator+(double d) // These only overload the Vector + int operator
{
for (int i=0; i<vSize; i++) {vData[i]=vData[i]+d;}
}
void operator*(double d)
{
for (int i=0; i<vSize; i++) {vData[i]=vData[i]*d;}
}
size_t vSize;
vector<double> vData;
};
With a function
Vector AddVec(Vector v1, Vector v2)
{
Vector totVec(v1.getSize());
for (int i=0; i<v1.getSize(); i++) {totVec(i) = v1(i) + v2(i);}
return totVec;
}
And the same function for 3 vectors.
Now I realise that the error means that I'm passing void to some function, but I cannot figure out where things go wrong. When I try writing a test program, everything seems to work fine.
Your operators return void
void operator+(double d) // These only overload the Vector + int
{
for (int i=0; i<vSize; i++) {vData[i]=vData[i]+d;}
}
void operator*(double d)
{
for (int i=0; i<vSize; i++) {vData[i]=vData[i]*d;}
}
So when you call AddVec(x, dydx*h) it calls AddVec(x, void)
You've overloaded operators that don't behave like the conventional ones, don't do that!!! Doing that gives C++ a bad name.
void operator*(double d)
{
for (int i=0; i<vSize; i++) {vData[i]=vData[i]*d;}
}
This doesn't return anything, so you can't use it like this:
z.fillRow(1,AddVec(x, dydx*h));
^^^^^^
operator* should return a new object, not modify its left operand. If you want to modify the left operand, use operator*= but you should still return something.
Vector& operator*=(double d)
{
for (int i=0; i<vSize; i++)
vData[i] *= d;
return *this;
}
Vector operator*(double d)
{
Vector v(*this);
v *= d;
return v;
}
The operator* would be better as a non-member, and should take its argument by reference:
Vector operator*(const Vector& v, double d)
{
Vector v2(v);
v2 *= d;
return v2;
}

Class inheritance, copy constructor and set/get functions

I got the following class:
class Matrix{
private:
int rows;
int columns;
double* matrix;
public:
Matrix();
explicit Matrix(int N);
Matrix(int M, int N);
void setValue(int M, int N, double value);
double getValue(int M, int N);
bool isValid() const;
int getRows();
int getColumns();
~Matrix();
friend ostream& operator<<(ostream &out, Matrix&matrix1);
Matrix &operator=(const Matrix &m) {
if (rows * columns != m.rows * m.columns){
delete [] this->matrix;
this->matrix = new double[m.rows * m.columns];
}
rows = m.rows;
columns = m.columns;
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
this->matrix[i * columns + j] = m.matrix[i * columns + j];
}
}
return *this;
}
Matrix(const Matrix &rhs);
};
with these functions
#include <iostream>
#include "Matrix.h"
using namespace std;
//OPPGAVE 2
Matrix::Matrix(){
matrix = NULL;
}
Matrix::Matrix(int N){
matrix = new double[N * N];
rows = N;
columns = N;
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
if(i==j)
matrix[i * N + j] = 1;
else
matrix[i * N + j] = 0;
}
}
}
Matrix::Matrix(int M, int N){
matrix = new double[M * N];
rows = M;
columns = N;
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++)
matrix[i * N + j] = 0;
}
}
Matrix::~Matrix(){
delete [] matrix;
}
void Matrix::setValue(int M, int N, double value){
matrix[M * columns + N] = value;
}
double Matrix::getValue(int M, int N){
return matrix[M * columns + N];
}
bool Matrix::isValid() const{
if(matrix==NULL)
return false;
else
return true;
}
int Matrix::getRows(){
return rows;
}
int Matrix::getColumns(){
return columns;
}
ostream& operator<<(ostream &out, Matrix&matrix1){
if(matrix1.isValid())
for(int i = 0; i < matrix1.getRows(); i++){
for(int j = 0; j < matrix1.getColumns(); j++)
out << matrix1.getValue(i,j) << "\t";
out << endl;
}
else
out << "Matrisen er ikke gyldig." << endl;
return out;
}
Matrix::Matrix(const Matrix &rhs) : rows(rhs.rows),
columns(rhs.columns),
matrix(new double[rows * columns]) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
this->matrix[i * columns + j] = rhs.matrix[i * columns + j];
}
}
}
The exercise says:
a) Create a class Vector that inherits the MxN Matrix.
We want to use the Vector class as an interface to an Mx1 dimensional matrix with some
extra functionality.
b) Implement the following constructors for the Vector class.
• Vector()
Default constructor, should initialize the underlying matrix into the invalid state.
• explicit Vector(unsigned int N)
Should construct the underlying Mx1 Matrix, initialized as a zero-matrix. (The explicit keyword is not in the syllabus, but it should be used here.)
• Vector(const Matrix & other);
Copy-constructor from Matrix. Should assign a matrix to *this if and only if the matrix has dimensions Nx1, otherwise the resulting *this should be set to invalid. Hint: Reuse operator= from the Matrix-class.
This is what I've got so far:
#include "Matrix.h"
class Vector : public Matrix{
public:
Vector();
explicit Vector(int N);
Vector(const Matrix & other);
};
and
using namespace std;
#include <iostream>
#include "Vector.h"
Vector::Vector()
:Matrix(){ }
Vector::Vector(int N)
:Matrix(N,1){ }
How am I supposed to reuse the operator= from Matrix? If I try to copy it from the Matrix class into the Vector class, it says that rows, columns etc is inaccessible. How do I access these?
Is it possible to write a copy constructor for the Vector class more or less the same as the copy constructor for the Matrix class? They are both arrays, so I guess it should work?
Will the operators I overloaded for Matrix (not included here) automaticly be used if I multiply a Matrix with a Vector, or do I also need to include these somehow in the Vector class? (They were written outside the Matrix class in the Matrix.cpp-file.)
Next Im going to write set and get functions for the Vector class.
Is it possible to write these functions on this form?:
void Vector::setValue(int i, double value) {
Matrix::setValue(i, 1, value);
}
Help and tips are greatly appreciated!
What follows is hideous kludgery to satisfy an incompetent professor. Don't do this in the real world.
First, the misnamed "copy" constructor. If we weren't worried about the dimensions, we could do this (shudder):
Vector(const Matrix & other)
{
*this = other;
}
But we must check the dimensions first. We could do it this way:
Vector(const Matrix & other)
{
if(other.getColumns()==1)
*this = other;
}
But some chucklehead neglected to make getColumns() const, so this results in a compiler error. We could do something truly drastic, const cast:
Vector(const Matrix & other)
{
Matrix *p = const_cast<Matrix *>(&other);
if(p->getColumns()==1)
*this = other;
}
Or just something facepalmingly awful:
Vector(const Matrix & other)
{
Matrix M(other); // notice that this is not const
if(M.getColumns()==1)
*this = other;
}
Do you need help with the isValid stuff?
You are on the right track for the sets and gets. You can call operators with member function like syntax Class::operator*(args). Implementing the vector assignment would look something like this:
Vector & Vector::operator=(const Vector &v){
Matrix::operator=(v);
return *this;
}
You will want your Vector constructors to be declared public. I am thinking because you are using inheritance the compiler will generate correct copy constructors and assignment operators for the Vector class. You should write tests to verify this assumption.