如何正确重载+运算符

时间:2013-11-18 11:49:49

标签: c++ operators operator-overloading

我正在尝试定义一个简单的类来处理2d矩阵,称为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;
}

3 个答案:

答案 0 :(得分:2)

Herb Sutter倡导者the following canonical way to overload operator +(请阅读GotW,它写得非常好并且很有趣):

  • 不要将operator +作为成员函数包含在内,而是将其作为自由函数。
  • 按值传递一个对象,另一个按const引用传递。这使得在添加临时操作时可以使用移动操作符。
  • 根据operator +=

    实施
    Matrix2D01 operator+(Matrix2D01 a, const Matrix2D01 &b)
    {
        a += b;
        return a;
    }
    

答案 1 :(得分:1)

我发布了我上次Sem为离散数学作业编写的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

答案 2 :(得分:1)

您的操作数应为const引用。否则,你 不能使用临时来初始化它们。 (在这种情况下, operator+的返回值是临时的,因此不能 绑定到operator=的非const引用。)

如果您的operator+是成员,那么它也应该是常量。 毕竟,它并没有修改它所调用的对象。所以:

Matrix2D01& Matrix2D01::operator=( Matrix2D01 const& mat2 );
Matrix2D01& Matrix2D01::operator+=( Matrix2D01 const& mat2 );
Matrix2D01 Matrix2D01::operator+( Matrix2D01 const& mat2 ) const;

此外,您的分配操作符已损坏。 (想想会发生什么 如果其中一个分配在您释放后失败,则会发生 原始数据。)一般情况下,如果你必须测试自己 赋值,赋值运算符被破坏。