3

Tengo una clase Matrix que tiene un constructor de copia y un metodo add que suma la matriz con otra y devuelve una nueva matriz, pero no puedo usar el constructor copia con este metodo.

#include <iostream>
#include "matrix.h"
#include "methods.h"

using namespace std;
int main()
{
    unsigned int n;
    cin >> n;
    Matrix a(n,n);
    cin >> a;
    Matrix b(a);
    Matrix c(a.add(b));
    c.print();
}

La linea Matrix b(a) funciona sin errores y el metodo add funciona de manera correcta pero la linea Matrix c(a.add(b)) me produce el error: no matching constructor for initialization of 'Matrix'. Si utilizo a.add(b).print() funciona todo correctamente. porque no puedo pasar el resultado del metodo al constructor??

Esta es la clase Matrix:

Matrix::Matrix() : Matrix(3, 3){}

Matrix::Matrix(unsigned int rows, unsigned int cols){
    this->rows = rows;
    this->cols = cols;
    this->array = std::vector<std::vector<double>>(rows, std::vector<double>(cols));
    fill(0);
}

Matrix::Matrix(Matrix& m) : Matrix(m.getRows(), m.getCols()){
    array = m.array;
}

void Matrix::map(std::function<double(unsigned int i, unsigned int j)> f){
    for(unsigned int i = 0; i < rows; i++){
        for(unsigned int j = 0; j < cols; j++){
            array[i][j] = f(i, j);
        }
    }
}

void Matrix::fill(double d){
    map([&](int, int)->double{ return d;});
}

void Matrix::print(){
    for (unsigned int i = 0; i < rows; ++i) {
        std::cout << array[i][0];
        for (unsigned int j = 1; j < cols; ++j) {
            std::cout << " " << array[i][j];
        }
        std::cout << std::endl;
    }
}

unsigned int Matrix::getRows(){
    return rows;
}

unsigned int Matrix::getCols(){
    return cols;
}

Matrix Matrix::add(Matrix m){
    assert(rows == m.rows && cols == m.cols);
    Matrix res(rows, cols);
    res.map([&](unsigned int i, unsigned int j)->double{ return array[i][j]+m.array[i][j];});
    return res;
}
...
Joaquin
  • 43
  • 3

1 Answers1

3

Las funciones involucradas son estas:

Matrix::Matrix(Matrix& m)
Matrix Matrix::add(Matrix m);

Es decir, el constructor espera recibir un L-value (recomiendo leer esta otra pregunta) y, sin embargo, la función add devuelve un R-value y la conversión pedida no es válida.

Dicho con otras palabras, la conversión no es válida porque add devuelve un objeto por valor. Y el único receptor de dicho objeto es el constructor copia, es decir, tras la llamada el objeto va a dejar de existir. Este ciclo de vida tan corto impide que puedas pasarlo como referencia sin más... la referencia debe ser, en este caso, constante:

Matrix::Matrix(Matrix const& m);
//                    ~~~~~ Importante!!!

Ahora bien, si haces este cambio el código seguirá sin compilar porque este constructor intenta llamar a getRows() y getCols() y estos métodos no están etiquetados como const, luego no pueden ser llamados si el objeto es constante. La solución a este problema es tan simple como etiquetar estos métodos como const (algo que tiene sentido ya que estos métodos no deberían modificar el estado del objeto actual):

unsigned int getRows() const;
unsigned int getCols() const;
eferion
  • 49,291
  • 5
  • 30
  • 72