Переопределяем двойные квадратные скобки на 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 [3662 просмотра]