C++运算符重载无法输出+运算

C++ operator overloading fails to output + operation

我正在学习 C++ 并尝试为矩阵编写 C++ class,我将矩阵存储为一维 C 数组。为此,我定义了一个 element 成员函数来根据矩阵元素在数组中的位置访问它们。然后我重载了 <<+ 运算符来处理矩阵的显示和添加。 << 运算符按预期工作,如下例所示:

#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;
}

然后我无法显示两个矩阵的加法:

    std::cout << A+B << std::endl;

但是,如果我在显示它们的总和之前分解操作并分别添加矩阵,我会得到正确的输出,这让我相信 + 运算符也能正常工作:

    matrix C(2,2);
    C = A+B;
    std::cout << C << std::endl;

该错误似乎表明将矩阵元素转换为 ostream 时可能存在问题,但奇怪的是上述变通解决方案是否有效。

您的 << 运算符将对矩阵的非常量引用作为参数。这意味着它不能引用临时对象。 A+B 的结果是一个临时对象,如果你不将它分配给某些东西的话。

所以你需要改变这个:

std::ostream & operator<<(std::ostream &os, matrix &M);

进入这个:

std::ostream & operator<<(std::ostream &os, const matrix &M);

您的 + 接线员可能迟早会遇到同样的问题:

matrix operator+(matrix &M)

应该是

// Both `M` and `*this` should be const
matrix operator+(const matrix &M) const

当然你的 element 方法会遇到问题,它只能作用于非常量对象,所以你还需要一个作用于常量对象的变体:

class matrix
{
   ....
 public:
   double & element(int r, int c);
   double element(int r, int c) const;
   ...
}

您不能对临时对象进行非const引用。您正在尝试使用临时 (A+B) 调用 operator<<,但重载 operator<< 的签名采用非 const 引用,因此您的函数无效候选人。

要解决此问题,您需要进行一些更改。首先,让重载的 << 运算符对矩阵进行 const 引用。并且不要忘记在 class 声明中修复 friend 签名。

std::ostream & operator<<(std::ostream &os, const matrix &M);

只是这样做仍然会导致错误,因为 element 方法只为非 const 对象定义。您需要为 element 添加一个重载,它作用于 const matrixes(并且不会让您修改返回的元素)。

double matrix::element(int i, int j) const
{
    int loc = (j-1) + (i-1)*columns;
    return array[loc];
}

你的operator<<operator+都需要通过const引用来获取输入matrix,这样他们才能接受临时matrix 对象作为输入。

此外,operator+ 应该是 const 限定的,因为它不会修改 this 的内容。 element() 应该有一个 const 限定的重载,这样它就可以提供对 const matrix 对象的只读访问。

根据 Rule of 3/5/0,您还缺少复制构造函数、复制赋值运算符、移动构造函数和移动赋值运算符。而且,你的析构函数根本没有释放 C 数组,所以它被泄露了。

试试这个:

#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;
}