2016-12-12 12 views
1

Я пытаюсь использовать перегрузку оператора с помощью оператора + и = на классе матрицы, который я создал. либо конструктор, либо деструктор вызывает проблему, либо он не является (хотя я неактивен для каждого из них, и оба и код, похоже, работают). кто-то может помочь мне понять, что вызывает это странное поведение. когда я пытаюсь создать 3 матрицы a b и c, тогда попробуйте a = b + c; он просто терпит неудачу.конструктор деструктор или понимание ООП

header file 
#ifndef MATRIX_H; 
#define MATRIX_H; 
using namespace std; 


enter code here 

class matrix 
{ 
friend ostream& operator<< (ostream&, matrix &); 
public: 
    matrix(); 
    matrix(int,int); //constructor 
    matrix(const matrix&);//copy constructor 
    ~matrix(); 
    int getRow(); 
    int getCol(); 
    void setRow(int); 
    void setCol(int); 
    class arr1D{    //proxy class to allow the use of [][]  operator 
     public: 
     arr1D(int* a):temp(a){} 
     int &operator[](int a){ 
      return temp[a]; 
     } 
     int *temp; 
    }; 
    arr1D operator[](int a){ 
    return arr1D(arr2[a]); 
    } 
    matrix& operator=(const matrix&); 

    matrix& operator+(const matrix&); 

protected: 
private: 
    int row , col; 
    int **arr2; 

    }; 

    #endif // MATRIX_H 

enter code here 
cpp file 
#include <iostream> 
#include "matrix.h" 

using namespace std; 

matrix::matrix() 
{ 
setCol(0); 
setRow(0); 
**arr2=0; 
} 


matrix::matrix(int x, int y) //matrix constructor creates x*y matrix and     initializes to 0's 
{ 
setCol(y); 
setRow(x); 
arr2 = new int * [getRow()]; 
if (arr2) { 
    for (int i = 0; i < getRow(); i++) { 
     arr2[i] = new int [getCol()]; 

    }; 
}; 
for (int i=0; i<getRow();i++){ 
    for (int j=0;j<getCol();j++){ 
     arr2[i][j]=0; 
    }; 
}; 
} 

matrix::matrix(const matrix &m){ //defines the copying constructor 
row=m.row; 
col=m.col; 
arr2 = new int*[row]; 
for (int i=0; i<row; i++){ 
    arr2[i] = new int[col]; 
    } 
for (int i=0; i<row; i++){ 
    for (int j=0; j<col; j++){ 
     arr2[i][j] = m.arr2[i][j]; 
    } 
} 

} 

matrix::~matrix(){ //defines the destructor 
for (int i=0; i<row; i++){ 
    delete[] arr2[i]; 
    } 
delete[] arr2; 
} 


int matrix::getRow(){ //getter for row 
return row; 
} 

int matrix::getCol(){ // getter for col 
return col; 
} 

void matrix::setRow(int x){ //setter for row 
row=x; 
} 

void matrix::setCol(int x){ //setter for col 
col=x; 
} 


ostream& operator<< (ostream& output, matrix& a){ 
    int i,j; 
    for (i=0; i < a.getRow() ; i++){ 
     for (j=0; j< a.getCol() ; j++){ 

      output << " " <<a.arr2[i][j]; 

     }; 
     output << "\n"; 
    }; 
return output; 
} 

matrix& matrix::operator=(const matrix& right) 
{ 
if (this == &right) {  // Same object? 
    return *this; 
} 
row = right.row; 
col = right.col; 
for (int i=0; i<row; i++) 
{ 
    for (int j=0; j<col; j++){ 
    arr2[i][j]=right.arr2[i][j]; 
    } 
} 
return *this ; 
} 

matrix& matrix::operator+(const matrix& right) 
{ 
int row=right.row; 
int col=right.col; 
matrix result(row,col); 
for (int i = 0; i < row; i++){ 
    for (int j = 0; j < col; j++){ 
      //cout<<"arr2[i][j]="<<arr2[i][j]<<endl; 
      //cout<<"right.arr2[i][j]="<<right.arr2[i][j]<<endl; 
     result.arr2[i][j]=(arr2[i][j] + right.arr2[i][j]); 
      //cout<<"result.arr2[i][j]="<<result.arr2[i][j]<<endl; 
    }; 
}; 
return result; 
} 
+0

Под файлом cpp i выделено «// определяет конструктор копирования». возможно, я объявил это неправильно? я действительно в темноте здесь. –

ответ

1

Во-первых, как другой ответ указал, вы возвращаете ссылку на временный в вашем operator +. Это неопределенное поведение.

Но вместо того, чтобы писать operator + таким образом, что вы должны сделать, это написать operator += вместо этого, а затем, в свою очередь, пишут operator + с точки зрения operator +=. Поскольку программист ожидал бы, что += также будет работать для matrix в дополнение к +, нет смысла уходить +=.

Для operator += вы бы в этом случае возвращали ссылку на текущий объект.

Так все, что нужно сделать, это переместить код в operator + к operator +=:

#include <exception> 
//... 
matrix& matrix::operator+=(const matrix& right) 
{ 
    if(row != right.row || col != right.col) 
     throw std::logic_error("Matrix not the same size"); 

    for (int i = 0; i < right.row; i++) 
    { 
     for (int j = 0; j < right.col; j++) 
      arr2[i][j] += right.arr2[i][j]); 
    } 
    return *this; 
} 

Обратите внимание, что мы возвращаем ссылку на текущую матрицу, так как += изменяет текущую матрицу. Также обратите внимание, что мы высылаем исключение из недопустимой матрицы, отправляемой на +=. Эта ИМО имеет больше смысла, чем возвращение законного matrix обратно на ошибку. Если матрица не того же размера, код не должен пытаться вернуть матрицу обратно.

Теперь operator + можно записать в терминах +=:

matrix matrix::operator+(const matrix& right) 
    { 
     return matrix(*this) += right; 
    } 

Верьте или нет, это все. Все, что мы сделали, это создать временную матрицу и вызвать += с переданным аргументом. Мы вернем результат этого как совершенно новую матрицу, как и ожидаем.

Другая проблема - оператор присваивания. Учитывая, что вы написали конструктор и деструктор копии, а конструктор копирования работает без использования оператора присваивания, то для реализации оператора присваивания можно использовать copy/swap idiom.

#include <algorithm> 
    //... 
    matrix& matrix::operator=(const matrix& right) 
    { 
     matrix temp(right); 
     std::swap(temp.arr2, arr2); 
     std::swap(temp.row, row); 
     std::swap(temp.col. col); 
     return *this; 
    } 

Все, что мы сделали здесь было создать временную матрицу переданного в объекте и выгрузить его содержимое с содержимым текущего объекта. Когда временное отмирает при возврате, временное уничтожение старого содержимого, которое было заменено.

Этот метод имеет то преимущество, что он не только очень прост в реализации (просто куча звонков на std::swap), но и безопасна. Если возникнет проблема с созданием временной матрицы, было бы исключено исключение std::bad_alloc, не вмешиваясь и не изменяя любые элементы this. Проблема с другим ответом, в котором вы освобождаете память перед распределением новой памяти, решается с помощью вышеупомянутой техники.

+0

в операторе присваивания (=).вы используете матрицу temp (right) ;, эта операция вызывает конструктор копирования? и в конце - на что (на что это ссылается)? к матрице времен или матрице на левом операторе? Еще раз спасибо, я сожалею о хлопот, я просто чувствую, что мне не хватает понимания того, что происходит в памяти. –

+0

Да, конструктор копирования вызывается, когда вы выполняете «temp tem templates (right)»; поэтому для копирования/замены требуется конструктор копирования. '* This' является текущей матрицей. – PaulMcKenzie

+0

спасибо большое, имеет больше смысла! –