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.
Related
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.
I got a class Matrix and a class Row. Matrix has as member variable a pointer to a pointer of an object from class Row. I overloaded the operator [] for Matrix and Row. But somehow the overloaded operator from Row is never getting called and I can't figure out why not.
Example Code:
matrix.h
class Row
{
int* value;
int size;
public:
int& operator[](int i)
{
assert(i >= 0 && i < size);
return value[i];
}
};
class Matrix
{
private:
Row **mat; // Pointer to "Row"-Vector
int nrows, ncols; // Row- and Columnnumber
public:
Row& Matrix::operator[](int i){
assert(i >= 0 && i < nrows);
return *mat[i];
}
Row** getMat() {
return mat;
}
// Constructor
Matrix(int rows, int cols, int value);
};
matrix.cpp
#include "matrix.h"
Matrix::Matrix(int rows, int cols, int value) : nrows(rows), ncols(cols){
mat = new Row*[rows];
for(int i = 0; i < rows; i++) {
mat[i] = new Row(ncols);
for(int j = 0; j < ncols; j++){
// the operator-overload of Row[] isn't getting called and I don't get why not
mat[i][j] = value;
}
}
}
int main(){
Matrix m = new Matrix(2, 2, 4);
return 0;
mat[i] gives you Row*, and you want to call Row::operator[], but pointer to Row is not dereferenced automatically. So you have to dereference it manually: (*mat[i])[j].
So I just figured it out myself.
I tried to call the []-operator from Matrix through mat[][], but since mat is a Row** Row& Matrix::operator[](int i) is never getting called.
I have trouble understanding the problem in the title.
So there are my two classes, a Vector of 3 doubles and a 2D dynamic Matrix that has a Vector object in every cell.
The constructor of Matrix works and does not throw errors. However, when I want to refer to a cell of created Matrix instance in the ostream overload, I'm getting
"no match for 'operator[]' (operand types are 'Matrix' and 'int')"
Why is it OK to use the [][] notation during initialization and not OK later?
Is there a moderately straightforward way to fix this?
Many thanks!
class Vector{
private:
double x, y, z;
public:
Vector(){
x = y = z = 0;
}
Vector(int x_, int y_, int z_){
x = x_;
y = y_;
z = z_;
}
friend ostream &operator<< (ostream &wyj, Vector &v);
friend istream &operator>> (istream &wej, Vector &v);
};
/// ===== MATRIX CLASS CONSISTS OF VECTOR OBJECTS
class Matrix{
private:
Vector ** M;
int row;
int col;
public:
Matrix(int col, int row){
M = new Vector * [row];
for(int i = 0; i < row; i++){
M[i] = new Vector[col];
}
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
M[i][j] = Vector();
}
}
}
friend ostream &operator<< (ostream &wyj, Matrix &M);
};
ostream &operator<< (ostream &wyj, Matrix &M){
for(int i = 0; i < M.row; i++){
for(int j = 0; j < M.col; j++){
wyj << M[i][j] << " ";
}
wyj<< endl;
}
return wyj;
}
int main(){
Matrix A(2, 2);
cout << A[1][1]; // LURD VADAR SAYZ NOOOOOOOOOOOOOOO
}
EDIT: minor typos in << overload method
Why is it OK to use the [][] notation during initialization and not OK
later?
In Matrix's constructor M is a Vector**. In main() A is a Matrix. So [][] is ok for a Vector**, but not meaningful (unless defined) for Matrix.
Is there a moderately straightforward way to fix this?
For [][] to work you need to have operator[] defined twice. Once for the first object and once for the object returned by the first operator[].
So in Matrix you could include:
Vector* operator[](size_t index) { return M[index]; }
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.
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.