0

I got a homework which looks something like this. I am working on it and hold beginner knowledge of the same. I have to create a header file that contains this code and then use the header file to get the desired results.

I am working with C++ template, and operator overloading.

#include <iostream>
#include <memory>
#include "matrix.h"
#include "symetric_matrix.h"

using namespace std;

int main()
{
    const Matrix<int, 3, 2> m1; // Creates 3*2 matrix, with all the default elements set to 0;
    cout << m1 << endl;
    Matrix<int, 3, 3> m2(4); // Creates 3*3 matrix, with the default elements equals to 4;
    cout << m2 << endl;
    const Matrix<int, 3, 3> m3 = m2; // C-py constructor may take O(MN) and not O(1).
    cout << m3 << endl;

    // min() returns the minimal value in the matrix.
    if (min(m1) < min(m3))
        cout << "Min value of m3(" << min(m3) << ") is bigger than min value of m1(" << min(m1) << ")" << endl;

    if (m1.avg() < m3.avg()) // Compares the average of the elements
        cout << "Average value of m3(" << m3.avg() << ") is bigger than average value of m1(" << m1.avg() << ")" << endl;

    m2(0, 0) = 13;
    cout << m2[0][0] << " " << m2[1][0] << endl; // Should print "13 4"

    try
    {
        cout << m2 + m3 << endl;
        cout << m3 * m1 << endl; // You can choose the format of matrix printing;
        cout << m1 * m2;         // This should throw an exception
    }
    catch (const Matrix<int, 3, 2>::IllegalOperation &e)
    {
        cout << e.what() << endl;
    }

    Matrix<int, 3, 3> m4;
    m4 = m3;
    cout << m4 << endl;
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            m4(i, j) = i + j;
    cout << m4 << endl;

    cout << "m4[1][1] = " << m4[1][1] << endl;

    cout << "m4[1][1] = " << m4(1, 1) << endl; // m4(1,1) same result as m4[1][1]

    Matrix<int, 3, 3> m5(3);
    m5 = 2 * m4;
    cout << m5 << endl;
    Matrix<int, 3, 3> m6(m4);
    cout << m6 << endl;
    m5 += m4;
    cout << m5 << endl;

    if (m6 != m5)
        cout << "m6 != m5" << endl;

    Matrix<Matrix<int, 3, 2>, 4, 4> composite(m1); // Creates matrix, where each element is m1;

    cout << composite;

    unique_ptr<Matrix<int, 3, 3>> symetric_matrix(new SymetricMatrix<int, 3>(5)); // SymetricMatrix matrix 3*3 with default element equals to 5;

    (*symetric_matrix)(1, 2) = 8;
    cout << (*symetric_matrix)(1, 2) << " " << (*symetric_matrix)(2, 1) << endl; // Should print "8 8"
    cout << (*symetric_matrix)[1][2] << " " << (*symetric_matrix)[2][1] << endl; // Should print "8 8"

    (*symetric_matrix)[1][0] = 18;
    cout << (*symetric_matrix)[1][0] << " " << (*symetric_matrix)[0][1] << endl; // Should print "18 18"

    return 0;
}

My Updated solution for now.

template <class T, int M, int N>
class Matrix
{
private:
    T mat[M][N];
    int rows = M;
    int cols = N;

public:
    // constructor
    Matrix(int v = 0)
    {
        for (int i = 0; i < M; i++)
        {
            for (int j = 0; j < N; j++)
                mat[i][j] = v;
        }
    }

    Matrix<T, M, N> operator+(Matrix<T, M, N> &other);
    Matrix<T, M, M> operator*(T scalar);

    T &operator()(int i, int j)
    {
        return mat[i][j];
    };

    T *operator[](int index)
    {
        return mat[index];
    };

    // << overloading
    friend std::ostream &operator<<(std::ostream &os, const Matrix<T, M, N> &L)
    {
        for (int i = 0; i < M; i++)
        {
            for (int j = 0; j < N; j++)
                os << L.mat[i][j] << " ";
            os << "\n";
        }
        return os;
    };

    friend T min(Matrix obj)
    {
        T result = obj.mat[0][0];
        for (int i = 0; i < M; i++)
        {
            for (int j = 0; j < N; j++)
                if (result < obj.mat[i][j])
                    result = obj.mat[i][j];
        }
        return result;
    };

    long double avg() const
    {
        long double result = 0;
        for (int i = 0; i < M; i++)
        {
            for (int j = 0; j < N; j++)
                if (result < mat[i][j])
                    result = result + mat[i][j];
        }
        return result / (M * N);
    }
};

template <class T, int M, int N>
Matrix<T, M, N> Matrix<T, M, N>::operator+(Matrix &other)
{
    if ((this->rows == other.rows) && (this->cols == other.cols()))
    {
        Matrix<T, M, N> resultantMatrix;

        for (auto i = 0; i < this->rows; i++)
        {
            for (auto j = 0; j < this->cols; j++)
            {
                auto &valueFirst = this->data[i][j];
                auto &valueSecond = other(i, j);

                if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
                    throw std::out_of_range("Resultant value of matrix is out of range");
                else
                    resultantMatrix(i, j) = valueFirst + valueSecond;
            }
        }
        return resultantMatrix;
    }
    else
        throw std::runtime_error("Matrices cannot be added, sizes do not match");
}

I am confused about m2(0,0) = 13 & cout << m2+m3, how does this work and how is this possible? I just need help with the whole program while I try and learn! Any help is appreciated.

Van Wilder
  • 444
  • 4
  • 14
  • 1
    You'll need to implement `operator()` (see here: https://stackoverflow.com/questions/317450/why-override-operator), and `operator[][]` (see here: https://stackoverflow.com/questions/6969881/operator-overload). – wohlstad Jun 11 '22 at 12:05
  • 1
    With `operator()` you can take the row and column as argument and return a reference to the value in the matrix and then assignment will alter the matrix. With `operator[]` you can only take one argument so you have to return a proxy object that remembers the matrix and row and has an `operator[]` taking the column argument and returning a reference to the value in the matrix. If your matrix is made up of vectors then the first `operator[]` can just return a reference to the vector. – Goswin von Brederlow Jun 11 '22 at 12:21
  • @GoswinvonBrederlow since this is a fixed-size 2D array, one can just return `mat[r]` from `operator[]`. No need for a custom proxy object. Not that I would recommend this. – n. m. could be an AI Jun 11 '22 at 12:28
  • I looked at both, I am trying to implement it but it is not working, can you tell me how it will be in my case? ```Matrix operator()(int i, int j) { return mat[i][j]; };``` This is my try. – Van Wilder Jun 11 '22 at 12:47
  • @n.1.8e9-where's-my-sharem. that would be returning a reference to the vector. – Goswin von Brederlow Jun 11 '22 at 12:52
  • `operator()` needs to return a `T&`, not a Matrix. And you should also have a const version of it. – Goswin von Brederlow Jun 11 '22 at 12:53
  • @VanWilder Refer to [Template Matrix Class: implemented some basic functionalities](https://codereview.stackexchange.com/questions/237962/template-matrix-class-implemented-some-basic-functionalities). – Jason Jun 11 '22 at 12:56
  • How do I implement the `[]` one, the current one gives me an error. `invalid types ‘int[int]’ for array subscript` ```T &operator[](int index) { return mat[index]; };``` Help me with this too. – Van Wilder Jun 11 '22 at 13:04
  • @VanWilder This is also given in the last shared [link](https://codereview.stackexchange.com/a/237995). – Jason Jun 11 '22 at 13:07
  • Never put `using namespace std;` in a header file!!! Also don't forget the guard clauses. – JHBonarius Jun 11 '22 at 13:11
  • Got it, Anoop Rana, I can't find the usecase there unless, I am missing something. – Van Wilder Jun 11 '22 at 13:19
  • @GoswinvonBrederlow according to my calculations that would be returning a pointer to a T. – n. m. could be an AI Jun 11 '22 at 13:19
  • `T &operator[](int index)` -> `T* operator[](int index)`. – n. m. could be an AI Jun 11 '22 at 13:20
  • @VanWilder You can search the keyword `[]` [here](https://codereview.stackexchange.com/a/237995) and you'll find it and use it as a reference. – Jason Jun 11 '22 at 13:31
  • @n.1.8e9-where's-my-sharem. one more reason for a proxy object. – Goswin von Brederlow Jun 11 '22 at 13:33
  • @GoswinvonBrederlow There is no reason to have any kind of `operator[]`, but if you decide, [against reason](https://isocpp.org/wiki/faq/operator-overloading#matrix-array-of-array), to have one, you might just as well save some typing and use `T*` as your proxy object. – n. m. could be an AI Jun 11 '22 at 13:57
  • I would define `constexpr T& operator[](std::size_t row, std::size_t col) { return mat[row][col]; }` with `-std=c++23` if I had to. The matrix should also have a row and column view to make `operator*` simpler. – Goswin von Brederlow Jun 11 '22 at 14:05
  • How will I do the multiplication, I don't understand the example Anoop Rana linked me to. How do I incorporate into my example, if you can link me to a website where I can learn. – Van Wilder Jun 11 '22 at 14:26
  • @VanWilder In the [link](https://codereview.stackexchange.com/questions/237962/template-matrix-class-implemented-some-basic-functionalities), there they have implemented the multiplication using `operator*`. Do you have doubts from that implementation? If yes, you can ask those doubts as separate questions explaining in detail which part you don't understand and which part you do understand. – Jason Jun 11 '22 at 15:07
  • ```error: no match for call to ‘(const Matrix) (int&, int&)’ 84 | auto &valueSecond = other(i, j); | ~~~~~^~~~~~ matrix.h:20:8: note: candidate: ‘T& Matrix::operator()(int, int) [with T = int; int M = 3; int N = 3]’ (near match) 20 | T &operator()(int i, int j) | ^~~~~~~~ matrix.h:20:8: note: passing ‘const Matrix*’ as ‘this’ argument discards qualifiers``` I am getting this while addition. – Van Wilder Jun 11 '22 at 15:36

0 Answers0