Пример создания шаблонного класса Матрица с динамическим выделением памяти
В примере демонстрируется создание шаблонного класса MATRIX. Класс реализует матрицу размером m*n. Память для матрицы выделяется динамически.
По данному примеру можно создавать и использовать собственные классы, которые содержат структуры данных в которых память выделяется динамически.
В классе реализованы:
- скрытая (private) внутренняя переменная M типа «указатель на указатель». Эта переменная определяет матрицу. Память для матрицы будет выделяться динамически;
- две целочисленные внутренние private-переменные m, n. Эти переменные определяют размерность матрицы M;
- конструктор по умолчанию (без параметров);
- конструктор с двумя параметрами MATRIX(int, int). Этот конструктор создает матрицу размером m*n. В конструкторе выделяется память для столбцов и строк матрицы. Значение каждого элемента матрицы устанавливается в 0;
- конструктор копирования MATRIX(MATRIX&). Этот конструктор необходим для создания копии объекта-матрицы из другого объекта-матрицы;
- методы чтения/записи элементов матрицы GetMij(), SetMij();
- метод Print(), который выводит матрицу;
- оператор копирования operator=(MATRIX&). Этот оператор перегружает оператор присваивания = и предназначен для корректного копирования объектов типа obj2=obj1;
- деструктор.
Реализация класса для приложения типа Console Application имеет следующий вид
#include <iostream> using namespace std; // шаблонный класс Матрица template <typename T> class MATRIX { private: T** M; // матрица int m; // количество строк int n; // количество столбцов public: // конструкторы MATRIX() { n = m = 0; M = nullptr; // необязательно } // конструктор с двумя параметрами MATRIX(int _m, int _n) { m = _m; n = _n; // Выделить память для матрицы // Выделить пам'ять для массива указателей M = (T**) new T*[m]; // количество строк, количество указателей // Выделить память для каждого указателя for (int i = 0; i < m; i++) M[i] = (T*)new T[n]; // заполнить массив M нулями for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) M[i][j] = 0; } // Конструктор копирования - обязательный MATRIX(const MATRIX& _M) { // Создается новый объект для которого виделяется память // Копирование данных *this <= _M m = _M.m; n = _M.n; // Выделить память для M M = (T**) new T*[m]; // количество строк, количество указателей for (int i = 0; i < m; i++) M[i] = (T*) new T[n]; // заполнить значениями for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) M[i][j] = _M.M[i][j]; } // методы доступа T GetMij(int i, int j) { if ((m > 0) && (n > 0)) return M[i][j]; else return 0; } void SetMij(int i, int j, T value) { if ((i < 0) || (i >= m)) return; if ((j < 0) || (j >= n)) return; M[i][j] = value; } // метод, выводящий матрицу void Print(const char* ObjName) { cout << "Object: " << ObjName << endl; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) cout << M[i][j] << "\t"; cout << endl; } cout << "---------------------" << endl << endl; } // оператор копирования - обязательный MATRIX operator=(const MATRIX& _M) { if (n > 0) { // освободить память, выделенную ранее для объекта *this for (int i = 0; i < m; i++) delete[] M[i]; } if (m > 0) { delete[] M; } // Копирование данных M <= _M m = _M.m; n = _M.n; // Выделить память для M опять M = (T**) new T*[m]; // количество строк, количество указателей for (int i = 0; i < m; i++) M[i] = (T*) new T[n]; // заполнить значениями for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) M[i][j] = _M.M[i][j]; return *this; } // Деструктор - освобождает память, выделенную для матрицы ~MATRIX() { if (n > 0) { // освободить выделенную память для каждой строки for (int i = 0; i < m; i++) delete[] M[i]; } if (m > 0) delete[] M; } }; void main() { // тест для класса MATRIX MATRIX<int> M(2, 3); M.Print("M"); // Заполнить матрицу значеннями по формуле int i, j; for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) M.SetMij(i, j, i + j); M.Print("M"); MATRIX<int> M2 = M; // вызов конструктора копирования M2.Print("M2"); MATRIX<int> M3; // вызов оператора копирования - проверка M3 = M; M3.Print("M3"); MATRIX<int> M4; M4 = M3 = M2 = M; // вызов оператора копирования в виде "цепочки" M4.Print("M4"); }
Результат выполнения программы
Object: M 0 0 0 0 0 0 --------------------- Object: M 0 1 2 1 2 3 --------------------- Object: M2 0 1 2 1 2 3 --------------------- Object: M3 0 1 2 1 2 3 --------------------- Object: M4 0 1 2 1 2 3 ---------------------
Итог. Если память в классе выделяется динамически, то обязательно нужно реализовывать собственный конструктор копирования и оператор копирования.
⇑
Связанные темы
⇑