如何正确地重载+运算符

5

我正在尝试定义一个简单的用于处理二维矩阵的类,名为Matrix2D01,并且在+运算符方面遇到了问题。 我已经有了可正常工作的+=运算符,

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

+运算符被定义为:

Matrix2D01 Matrix2D01::operator+(Matrix2D01& mat2) {
    Matrix2D01 result(1,1); 
    result=*this;
    result+=mat2;
    return result;
}

当我尝试使用+运算符时,例如通过
mat3=mat1+mat2;

编译器报错:
../MatrixGames.cpp:17:12: error: no match for ‘operator=’ in ‘mat3 = Matrix2D01::operator+(Matrix2D01&)((* & mat2))’

如果有人能告诉我我做错了什么,那将不胜感激。
谢谢。
我还定义了一个等于操作符。
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;
}  

以下是完整的测试用例:

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

这个问题与运算符重载有关。https://dev59.com/62855IYBdhLWcg3wUCWC#4421719 - jbat100
这段代码存在几个问题。首先:ח 不是一个有效的 C++ 源码字符。其次, operator+ 应该声明为 const,并且可以使用非引用或 const 引用。同样地,operator+= 也应该接受非引用或 const 引用。你能否同时提供完整的测试用例? - Sebastian Mach
“no match for ‘operator=’” 表示您没有为另一个 Matrix2D01 定义 = 运算符(也许存在另一种运算符,可以删除自动的 = 运算符),因此 mat1+mat2 可以正常工作,但结果无法分配给 mat3。尝试创建一个 Matrix2D01& Matrix2D01::operator=(const Matrix2D01& other) - jozxyqk
感谢您的评论。对于这个ח,我很抱歉,那是一个打字错误。我已经定义了一个 = 运算符,我会在帖子中添加它。 - user3004480
operator+ 会修改并返回一个临时值。实现它最简单的方法是通过按值传递参数,而不是通过引用(如果编译器可以创建它,那么在函数中就不需要显式地创建临时对象,而且这样更加经济)。然后修改该值并将其返回。 - Damon
显示剩余2条评论
3个回答

2
Herb Sutter提倡以下典范的重载+运算符的方式(请阅读GotW,它写得非常好且有趣):
  • 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;
    }
    

1
我已经发布了我在离散数学上一个作业中编写的Matrix类的代码。 请注意赋值运算符和复制构造函数的实现方式,您只需编写一个赋值运算符(我建议您也编写一个复制构造函数)。
#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 --;
}

更新:
    result=*this;

在你的代码中,你试图使用赋值运算符为result分配*this的值,但没有定义赋值运算符,编译器找不到匹配项
编写一个赋值运算符重载将解决此问题。
如果你有一个复制构造函数,你可以这样做:
Matrix2D01 Matrix2D01::operator+(Matrix2D01& mat2) {
    Matrix2D01 result = *this;
    result+=mat2;
    return result;
}

编写赋值运算符:http://www.learncpp.com/cpp-tutorial/912-shallow-vs-deep-copying/
如果您对细节感兴趣,请参阅:http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html

@user3004480,你的Matrix2D01类没有定义赋值运算符。 - galdin
这不是等于运算符吗?它已经被定义了。 - user3004480
@user3004480 赋值运算符需要一个 const 参数。请查看我添加到答案中的链接。 - galdin
1
在赋值运算符参数前添加const解决了问题。谢谢。非常成功! - user3004480

1
你的操作数应该是const引用。否则,你不能使用临时变量来初始化它们。(在这种情况下,operator+的返回值是一个临时变量,因此不能绑定到非const引用的operator=中。)
如果你的operator+是一个成员函数,它也应该是const的。毕竟,它不修改被调用的对象。所以:
Matrix2D01& Matrix2D01::operator=( Matrix2D01 const& mat2 );
Matrix2D01& Matrix2D01::operator+=( Matrix2D01 const& mat2 );
Matrix2D01 Matrix2D01::operator+( Matrix2D01 const& mat2 ) const;

此外,你的赋值运算符是有问题的。(想一想,如果在释放原始数据后出现分配失败的情况会发生什么。)通常来说,如果必须测试自我赋值,则赋值运算符是有问题的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接