БлогNot. Переопределяем двойные квадратные скобки на C++

Переопределяем двойные квадратные скобки на C++

Речь о том, как переопределить оператор квадратных скобок [] "дважды", чтобы выражение вида a[i][j] работало в шаблоне класса из объектов любого скалярного типа, и слева, и справа от знака присваивания.

Вот здесь подобного не делалось, хотя способы организовать двумерный контейнер из стандартного вектора STL показаны.

Ничего лучше, чем ввести вспомогательный класс "строка матрицы" и в нём также переопределить оператор квадратных скобок, мне в голову не пришло.

Пример, показанный ниже, сработал, проверен в консолях QT 5.X и Visual Studio 2015.

#include <iostream>
#include <iomanip>
using namespace std;

template <typename T> class Matrix {
private:
 int n,m;
 T **data;
public:
  Matrix(int n=2, int m=2) {
   if (n < 2) n = 2;
   if (m < 2) m = 2;
   this->n = n;
   this->m = m;
   data = new T *[n];
   for (int i = 0; i < n; i++) {
    data[i] = new T [m];
    for (int j = 0; j < m; j++) data[i][j] = (T)0;
   }
  }

  class MatrixRow {
   private:
    Matrix & matr;
    size_t _row;
   public:
    MatrixRow (Matrix & m, size_t row) : matr(m), _row(row) {}
    MatrixRow (T * _array) : _row(_array) {}
    T & operator [] (size_t col) {
     return matr.data[_row][col];
    }
  };

  MatrixRow operator [] (size_t index) {
   return MatrixRow(*this, index);
  }

  void show (int width=4) {
   for (int i=0; i<n; i++) {
    for (int j=0; j<m; j++) cout << setw(width) << data[i][j];
    cout << endl;
   }
  }
};

int main() {
 Matrix <double> a(2,2);
 a[1][1] = 1;
 a[0][0] = a[1][1] + 1;
 a.show();
 cin.get();
 return 0;
}

Чуть более развёрнутый пример, где в класс добавлен переопределённый оператор умножения матриц и шаблон функции-"друга" для вывода матриц в консоль оператором <<

#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <climits>
using namespace std;

template <typename T> class Matrix {
 size_t n, m;
 T** data;
public:
 static void error(size_t n) { //Статический метод обработки ошибок
  const string msgs[] = { 
   "Normal shutdown", 
   "No memory",
   "Bad matrix multipilcation"
  };
  if (n > msgs->length() - 1) 
   cout << endl << "Unknown error " << n;
  else 
   cout << endl << msgs[n] << " ("<< n <<")";
  cout << endl << "Press ENTER to exit";
  cin.clear();
  cin.ignore(INT_MAX, '\n');
  exit(n);
 }
 Matrix(size_t n = 2, size_t m = 2) { //Конструктор с 2 размерностями
  if (n < 2) n = 2; this->n = n;
  if (m < 2) m = 2; this->m = m;
  data = new T * [n];
  if (!data) Matrix::error(1);
  for (size_t i = 0; i < n; i++) {
   data[i] = new T [m];
   if (!data[i]) Matrix::error(1);
   for (size_t j = 0; j < m; j++) data[i][j] = (T)0;
  }
 }
 virtual ~Matrix () {}
 class MatrixRow { //Встроенный служебный класс "строка матрицы"
  Matrix & _matr;
  size_t _row;
 public:
  MatrixRow(Matrix & _m, size_t row) : _matr(_m), _row(row) {}
  MatrixRow(T* _arr) : _row(_arr) {}
  T& operator [] (size_t _col) { return _matr.data[_row][_col]; }
 };
 MatrixRow operator [] (size_t index) {
  return MatrixRow (*this, index);
 }
 template <typename T2> friend ostream& operator << (ostream&, Matrix <T2>&);
  //Шаблон дружественного метода для вывода матрицы в консоль
 Matrix operator * (const Matrix & b) { //Умножение матриц
  if (this->m != b.n) Matrix::error(2);
  Matrix c(this->n,b.m);
  for (size_t i = 0; i < n; i++) {
   for (size_t j = 0; j < b.m; j++) {
    c[i][j] = 0;
    for (size_t k = 0; k < m; k++)
     c[i][j] += this->data[i][k] * b.data[k][j];
   }
  }
  return c;
 }
};

template <typename T> ostream& operator << (ostream& os, Matrix <T> & _a) {
 os.precision(2);
 for (size_t i = 0; i < _a.n; i++) {
  os << endl;
  for (size_t j = 0; j < _a.m; j++) {
   os << fixed << setw(8) << _a.data[i][j];
  }
 }
 return os;
}

int main(void) {
 Matrix <double> a(2, 2);
 a[0][0] = a[1][1] = 1.5;
 a[1][0] = a[0][1] = -1.5;
 cout << "A"; cout << a;
 Matrix <double> b(2, 3);
 b[0][0] = -1; b[0][1] = -2; b[0][2] = -3;
 b[1][0] = 1; b[1][1] = 2; b[1][2] = 3;
 cout << endl << "B"; cout << b;

 Matrix <double> c = a * b;
 cout << endl << "A*B"; cout << c;

 //Класс может работать и с другими скалярными типами данных:
 Matrix <char> d(3, 2); 
 for (size_t i = 0; i < 3; i++) {
  d[i][0] = 'A' + i;
  d[i][1] = d[i][0] + 1;
 }
 cout << endl << "D"; cout << d;

 cin.get(); return 0;
}

06.05.2019, 21:11 [1531 просмотр]


теги: программирование c++