4

我正在尝试创建一个动态矩阵的模板类。以我目前对 C++ 的了解,我设法解决了一些问题,但我陷入了复制构造函数和重载 operator=; 的困境。换句话说,我无法创建我的对象的副本。在我看来,这应该可行,但我的朋友编译器告诉我,我有 1 个错误:错误:将 'const Matrix' 作为 'int Matrix::getElement(int, int) [with T = int 的 'this' 参数传递]' 在此行丢弃限定符 [-fpermissive]:

m[i][j] = original.getElement(i, j);

当我想创建一个对象时:

Matrix<int> m = Matrix<int>(3, 3);

我的模板类在这里:

template<class T>class Matrix
{
 public:

  Matrix<T>(int lines, int columns)
  {
    this->lines = lines;
    this->columns = columns;
    T* aux = new T[this->lines * this->columns];
    m = new T*[lines];
    for (int i = 0; i < this->lines; i++)
    {
      m[i] = aux + (i * this->columns);
    }
    for (int i = 0; i < this->lines; i++)
    {
      for (int j = 0; j < this->columns; j++)
      {
        m[i][j] = 0;
      }
    }
  }

  Matrix<T>(const Matrix<T>& original)
  {
    columns = original.getColumns();
    lines = original.getLines();
    T* aux = new T[this->lines * this->columns];
    m = new T*[lines];
    for (int i = 0; i < lines; i++)
    {
      m[i] = aux + (i * this->columns);
    }
    for (int i = 0; i < lines; i++)
    {
      for (int j = 0; j < columns; j++)
      {
        m[i][j] = original.getElement(i, j);
      }
    }
  }

  virtual ~Matrix<T>()
  {
    /*for (int i = lines - 1; i > 0; i--)
    {
      delete m[i];
    }*/
    delete [] m;
  }

  T** getPointer()
  {
    return m;
  }

  int getLines () const
  {
    return lines;
  }

  int getColumns () const
  {
    return columns;
  }

  int getElement(int line, int column)
  {
    return m[line][column];
  }

  int setElement(int line, int column, T value)
  {
    m[line][column] = value;
  }

  Matrix<T>* getTranspose()
  {
    Matrix<T>* aux = new Matrix<T>(lines, columns);
    for (int i = 0; i < lines; i++)
    {
      for (int j = 0; j < columns; j++)
      {
        aux->setElement(i,j, m[j][i]);
      }
    }
    return aux;
  }

  Matrix<T> operator=(const Matrix<T> original)
  {
    columns = original.getColumns();
    lines = original.getLines();
    T* aux = new T[this->lines * this->columns];
    m = new T*[lines];
    for (int i = 0; i < lines; i++)
    {
      m[i] = aux + (i * this->columns);
    }
    for (int i = 0; i < lines; i++)
    {
      for (int j = 0; j < columns; j++)
      {
        m[i][j] = original.getElement(i, j);
      }
    }
  }

  friend std::ostream& operator<<(std::ostream& out, Matrix<T>& matrix)
  {
    out<<"Matrix:"<<std::endl;
    for (int i = 0; i < matrix.getLines(); i++)
    {
      for (int j = 0; j < matrix.getColumns(); j++)
      {
        out<<matrix.getElement(i, j)<<" ";
      }
      out<<std::endl;
    }
    return out;
  }

  friend std::istream& operator>>(std::istream& in, Matrix<T>& matrix)
  {
    std::cout << "Reading Matrix:\n";
    for (int i = 0; i < matrix.getLines(); i++)
    {
      for (int j = 0; j < matrix.getColumns(); j++)
      {
        std::cout << "Matrix[" << i << "][" << j << "]:";
        in >> matrix.m[i][j];
      }
      std::cout << std::endl;
    }
    return in;
  }

 private:
  T** m;
  int lines;
  int columns;
};

正如我从该错误中可以看出的那样,我正在创建 2 个引用同一内存块的对象,但我想创建 2 个引用具有相同内容的 2 个不同内存块的对象。

4

2 回答 2

10

在您的复制构造函数中

Matrix<T>(const Matrix<T>& original)

original被声明为 const 引用,这非常好。但是,这意味着您不能Matrix<T>在其上调用任何未声明为const函数的方法。

getElement函数未声明,const因此您不能在复制构造函数中使用它。通过将其声明为 const 函数来解决此问题:

int getElement(int line, int column) const  // <--- Note the 'const'
{
  return m[line][column];
}

这意味着:

  1. 可以在Matrixconst 对象上调用此函数(例如original在您的复制构造函数中)

  2. 您不能在内部执行任何getElement修改当前实例Matrix(即修改*this)的操作。

前者是我们想要的,后者没有问题,因为getElement它只是一个getter方法,所以不需要修改任何东西。

请注意,因此,最好始终将成员函数标记为const不应修改任何内容。这意味着您可以将它们应用于常量对象,这意味着编译器会告诉您是否错误地将代码放入实际修改某些内容的函数中。

最后的评论:正如 Tore Olsen 所指出的,该getElement函数可能应该返回一个类型的对象或引用,T而不是int.

于 2012-10-17T07:16:54.243 回答
1

正如我常说的,当你开始写作时const,你不能停到最后。因为一个 const 对象可以使用 const 方法并且只能使用 const 方法。但是,常量正确性对于 C++ 程序员来说很重要。我曾经读过一篇关于那个的文章,不幸的是它是用法语写的,但我认为用英语很容易找到。它解释了 const 正确性为您的程序带来了安全性。它有助于一些优化,但在这里我无法准确记住作者的观点。

于 2012-10-17T07:24:53.953 回答