Search code examples
c++ooptemplatesfriend

How to write a friend (operator) method in a template?


So I'm trying to overload the operator + in a template class. the code compiles and runs but crashes at the use of the operator +. tried so many things, I think it's a syntax problem? any advice would be appreciated!

The operator = is overloaded and works.

Matrix.h

template <int row, int col, class T = int>
class Matrix
{
    int rows;
    int cols;
    T** mat;

public:

    Matrix(int defVal = 0) {
        rows = row;
        cols = col;
        memory();

        for (int i = 0; i < rows; i++)
            for (int j = 0; j < cols; j++)
                mat[i][j] = defVal;
    }
    ~Matrix() {
        del();
    }

    Matrix(const Matrix& other) {
        *this = other;
    }

    const Matrix& operator=(const Matrix& other) {
        if (&other != this)
        {   
            rows = other.rows;
            cols = other.cols;
            del();
            memory();
            for (int i = 0; i < rows; i++)
                for (int j = 0; j < cols; j++)
                    mat[i][j] = other.mat[i][j];
        }
        return *this;
    }

    friend ostream& operator<<(ostream& os, const Matrix& m) {

        for (int i = 0; i < m.cols; i++)
        {
            for (int j = 0; j < m.rows; j++)
                os << m.mat[i][j] << " ";
            os << endl;
        }
        return os;
    }

    friend Matrix operator+(const Matrix& other, T num) {

        Matrix temp = other;

        for (int i = 0; i < temp.rows; i++)
            for (int j = 0; j < temp.cols; j++)
                temp.mat[i][j] += num;
        return temp;
    }

    void memory(){
        mat = new T * [rows];
        for (int i = 0; i < rows; i++)
            mat[i] = new T[cols];
    }

    void del(){
        for (int i = 0; i < rows; i++)
            delete[] mat[i];
        delete[] mat;
    }
};

main.cpp

int main() {

    Matrix<4, 4> mat;
    std::cout << mat << std::endl;

    Matrix<4, 4> identity(1);

    std::cout << identity + 3 << std::endl; //crashes here

return 0;
}

if you need other parts of the code let me know! Thanks in advance!


Solution

  • Your copy constructor and assignment looks suspicious, you del after changing rows and cols, without initialising anything. I expect it should be

    Matrix(const Matrix& other) : rows(0), cols(0), mat(nullptr) {
        *this = other;
    }
    
    const Matrix& operator=(const Matrix& other) {
        if (&other != this)
        {   
            del(); // clean up first
            rows = other.rows;
            cols = other.cols;
            memory();
            for (int i = 0; i < rows; i++)
                for (int j = 0; j < cols; j++)
                    mat[i][j] = other.mat[i][j];
        }
        return *this;
    }
    

    As an aside, I wouldn't use dynamic allocation here at all, and instead

    template <typename T, size_t rows, size_t cols>
    class Matrix
    {
        std::array<std::array<T, cols>, rows> mat;
    public:
        Matrix(T defVal = {}) {
            for (int i = 0; i < rows; i++)
                for (int j = 0; j < cols; j++)
                    mat[i][j] = defVal;
        }
    
        friend std::ostream& operator<<(std::ostream& os, const Matrix& m) {
            for (int i = 0; i < cols; i++)
            {
                for (int j = 0; j < rows; j++)
                    os << m.mat[i][j] << " ";
                os << std::endl;
            }
            return os;
        }
    
        friend Matrix operator+(Matrix other, T num) {
            for (int i = 0; i < rows; i++)
                for (int j = 0; j < cols; j++)
                    other.mat[i][j] += num;
            return other;
        }
    
        // No need for any special members
    };