Функция операции вывода friend ostream& operator<<(ostream&, Matrix&):
Данная функция не может быть членом класса, поэтому чтобы иметь доступ к приватным элементам класса, она объявлена "дружественной" функцией. Она имеет два параметра: ссылку на поток, который находится слева от знака операции <<, и ссылку на объект, который находится слева от знака операции, данные этого объекта и будут выводиться. Затем следует форматированный вывод в поток всех элементов массива и возвращается поток. Если требуется вывести данные в файл, нужно открыть его присоединением к потоку ofstream.
Функция операции ввода friend istream& operator>>(istream&, Matrix&):
Так же как и предыдущая, данная функция не может быть членом класса, а поэтому для доступа к приватным элементам класса объявлена "дружественной" функцией класса. Она так же имеет два параметра: ссылку на поток, который находится слева от знака >>, и ссылку объект, который находится слева от знака операции, в него и будут вводиться данные из потока. Затем следует ввод данных из потока в элементы массива и возвращается поток. Для ввода данных из файла, нужно открыть его присоединением к потоку ifstream.
Функции-члены dim write(ofstream&) и dim read(ifstream&):
Функции предназначены для вывода в файл и ввода из файла матриц в из двоичном представлении. Для этого необходимо передать в них соответствующую ссылку на открытый файл.
Функция void ERROR_MATRIX(dim):
Это функция-член, которая вызывается для фиксации некоторых ошибок при создании матриц и работе с ними, таких как отсутствие памяти, несогласованность размеров матриц при операции умножения, попытки вычислить отрицательную степень матрицы и т.п.
Листинг модуля с определением и реализацией класса матриц
// файл tmatr.cpp
#include <stdlib.h>
#include <mem.h> // для setmem()
#include <fstream.h>
#include <math.h>
typedef unsigned char dim;
template <class VARTYPE> class Matrix {
typedef Matrix Vector;
private:
VARTYPE *matr; // указатель на массив матрицы
dim m,n;// размеры матрицы
public:
// конструкторы и деструкторы:
Matrix() { matr=(VARTYPE*)0; m=n=0; }
Matrix(dim,dim=1); // Обычный конструктор
Matrix(const Matrix<VARTYPE>&); // Конструктор копирования
~Matrix() { delete [ ]matr; }
// доступ к элементам матрицы
dim size_row() { return m; }// число строк
dim size_col() { return n; }// число столбцов
VARTYPE& operator() (dim x) const { return (*this)(x,0); }// элементу
// перегруженные операции и функции:
Matrix<VARTYPE>& operator=(const Matrix<VARTYPE>&);
Matrix<VARTYPE>& operator=(const VARTYPE&);
Matrix<VARTYPE> operator^(int); // возведение в степень
Matrix<VARTYPE> operator!(); // транспонирование
VARTYPE determ(); // определитель матрицы
VARTYPE vmodul(); // модуль вектора
Matrix& Gauss(dim,dim); // преобразование по Гауссу
// (для получ. обратной и единичной матрицы)
// (для получ. верхнетреугольной матрицы)
Matrix minor(dim,dim); // возвращает указ. минор матрицы
Vector line(dim i) // возвращает вектор-строку матрицы
{ return extract(1,n,i,0); }
Vector column(dim j) // возвращает вектор-столбец матрицы
{ return extract(m,1,0,j); }
VARTYPE& operator() (dim,dim) const;// доступ к
Matrix<VARTYPE>& operator<<=(const Matrix &A) { return newsize(A.m,A.n)=A; }
// безусловное приравнивание матриц
Matrix<VARTYPE>& insert(const Matrix&, dim=0, dim=0);// вставить часть матрицы
Matrix<VARTYPE> extract(dim, dim, dim=0, dim=0);// извлечь часть матрицы
Matrix<VARTYPE>& newsize(dim, dim=1);// установить новые размеры
void swap_line(dim, dim);//обмен строками матрицы
void swap_column(dim, dim);// обмен столбцами матрицы
friend Matrix<VARTYPE> operator+(const Matrix<VARTYPE>&,const Matrix<VARTYPE>&);//A-B
friend Matrix<VARTYPE> operator-(const Matrix<VARTYPE>&,const Matrix<VARTYPE>&);//A-B
friend Matrix<VARTYPE> operator*(const Matrix<VARTYPE>&,const Matrix<VARTYPE>&);//A*B
friend Matrix operator*(const double&,const Matrix<VARTYPE>&); //k*A
friend Matrix operator*(const Matrix<VARTYPE>&, const double&); //A*k
friend ostream& operator<<(ostream&,Matrix<VARTYPE>&);
// потоковый вывод матрицы
friend int operator>>(istream&,Matrix<VARTYPE>&);
// потоковый ввод существ. матрицы
// 0 - без. ошибок, 1 - была ошибка
dim read(ifstream&); // файловое чтение и запись матрицы
dim write(ofstream&);// в ее внутреннем, двоичном представлении.
friend VARTYPE operator %(const Matrix<VARTYPE>&,const Matrix<VARTYPE>&);
//Функция ошибок
void ERROR_MATRIX(dim) const;
};
// Реализация класса матриц
template <class VARTYPE>
Matrix<VARTYPE>::Matrix(dim M, dim N)
{
m=M;
n=N;
matr=new VARTYPE[m*n];
if(!matr) ERROR_MATRIX(1);
setmem(matr,sizeof(VARTYPE)*m*n,0);
}
template <class VARTYPE>
Matrix<VARTYPE>::Matrix(const Matrix<VARTYPE> &M_Obj) //Конструктор копирования
{
m=M_Obj.m;
n=M_Obj.n;
matr=new VARTYPE[m*n];
if(!matr) ERROR_MATRIX(1);
movmem(M_Obj.matr, matr, sizeof(VARTYPE)*m*n);
}
template <class VARTYPE>
Matrix<VARTYPE>& Matrix<VARTYPE>::operator=(const Matrix<VARTYPE> &M_Obj)
{
m=M_Obj.m;
n=M_Obj.n;
matr=new VARTYPE[m*n];
if(!matr) ERROR_MATRIX(1);
movmem(M_Obj.matr,matr,sizeof(VARTYPE)*m*n);
return *this;
}
//Диагональ?
template <class VARTYPE>
Matrix<VARTYPE>& Matrix<VARTYPE>::operator=(const VARTYPE &f)
{
for(int i=0,j;i<m;i++) for(j=0;j<n;j++)
if(i==j) (*this)(i,j)=f;
else (*this)(i,j)=0;
return *this;
}
template <class VARTYPE>
Matrix<VARTYPE> Matrix<VARTYPE>::operator^(int q) // Степень
{
if (q>0)
{
for(Matrix M=*this; q>1; q--)
M=M*(*this);
return M;
}
if (q!=-1) ERROR_MATRIX(3);
// вычисление обратной метoдом преобразований Гаусса
if (n!=m) ERROR_MATRIX(4);
Matrix M(m,2*n);
M.insert(*this);
for(int i=0;i<M.m;i++)
M(i,i+M.m)=1;
for(i=0;i<M.m;i++)
M.Gauss(i,i);
return M.extract(M.m,M.m,0,M.m);
}
template <class VARTYPE>
Matrix<VARTYPE> Matrix<VARTYPE>::operator!() // Транспозиция
{ Matrix<VARTYPE> A(n,m);
for(int i=0, j; i<m; i++)
for(j=0; j<n; j++)
A(j,i)=(*this)(i,j);
return A;
}
template <class VARTYPE>
VARTYPE Matrix<VARTYPE>::determ() // рекурсивно находит определитель матрицы
{
if (n!=m) ERROR_MATRIX(4);
if (n==1)
return (*this)(0,0);
for(int i=0; i<m; i++)
if ((*this)(i,0))
{
static Matrix<VARTYPE> M;
M <<= *this;
VARTYPE d=M(i,0)*(i%2?-1:1);
return d*M.Gauss(i,0).minor(i,0).determ();
}
return 0.0;
}
template <class VARTYPE>
VARTYPE Matrix<VARTYPE>::vmodul() // Модуль вектора
{
VARTYPE d=0;
if (n!=1) ERROR_MATRIX(9);
static Matrix<VARTYPE> M;
M <<= *this;
for(int i=0; i<m; i++)
d=d+M(i,0)*M(i,0);
return sqrt(d);
}
template <class VARTYPE>
Matrix<VARTYPE>& Matrix<VARTYPE>::Gauss(dim M, dim N)
{
Matrix<VARTYPE>& A=*this;
if (!A(M,N)) ERROR_MATRIX(5);
for(int i=0,j;i<m;i++)
for(j=0;j<n;j++)
if (i!=M && j!=N)
A(i,j)-=A(M,j)*A(i,N)/A(M,N);
for(j=0;j<n;j++)
if (j!=N)
A(M,j)/=A(M,N);
for(i=0;i<m;i++)
A(i,N)=0;
A(M,N)=1;
return *this;
}
template <class VARTYPE>
Matrix<VARTYPE> Matrix<VARTYPE>::minor(dim M, dim N)// возвращ. матрицу без
{// строки y и столбца x
Matrix<VARTYPE> A(m-1,n-1);
for(int i=0,in=0,j,jn;i<m;i++)
if (i!=M)
{
for(j=0,jn=0;j<n;j++)
if (j!=N)
A(in,jn++)=(*this)(i,j);
in++;
}
return A;
}
template <class VARTYPE> // вставка
Matrix<VARTYPE>& Matrix<VARTYPE>::insert(const Matrix<VARTYPE> &A, dim M, dim N)
{
if (M+A.m>m || N+A.n>n) ERROR_MATRIX(6);
for(int i=0, j; i<A.m; i++)
for(j=0; j<A.n; j++)
(*this)(i+M,j+N)=A(i,j);
return *this;
}
template <class VARTYPE> // извлечение
Matrix<VARTYPE> Matrix<VARTYPE>::extract(dim LM, dim LN, dim M, dim N)
{
if (M+LM>m || N+LN>n) ERROR_MATRIX(7);
Matrix<VARTYPE> A(LM,LN);
for(int i=0, j; i<LM; i++)
for(j=0; j<LN; j++)
A(i,j)=(*this)(i+M,j+N);
return A;
}
template <class VARTYPE>
VARTYPE& Matrix<VARTYPE>::operator() (dim M, dim N) const
{ return *(matr+n*M+N); }
template <class VARTYPE>
Matrix<VARTYPE> operator+(const Matrix<VARTYPE> &A, const Matrix<VARTYPE>&B)
{
Matrix<VARTYPE> C=A;
for(int i=0,j; i<A.m; i++)
for(j=0; j<A.n; j++)
C(i,j)+=B(i,j);
return C;
}
template <class VARTYPE>
Matrix<VARTYPE> operator-(const Matrix<VARTYPE> &A, const Matrix<VARTYPE> &B)
{
Matrix<VARTYPE> C=A;
for(int i=0, j; i<A.m; i++)
for(j=0;j<A.n;j++)
C(i,j)-=B(i,j);
return C;
}
template <class VARTYPE>
Matrix<VARTYPE> operator*(const Matrix<VARTYPE> &A,const Matrix<VARTYPE> &B)
{
Matrix<VARTYPE> C(A.m,B.n);
if (A.n!=B.m)
{
if(A.m==3 && A.n==1 && B.m==3 && B.n==1)
{
C(0)=A(1)*B(2)-A(2)*B(1);
C(1)=A(2)*B(0)-A(0)*B(2);
C(2)=A(0)*B(1)-A(1)*B(0);
}
else
A.ERROR_MATRIX(2);
}
else
{
for(int i=0,j,k;i<C.m;i++)
for(j=0;j<C.n;j++)
for(k=0;k<A.n;k++)
C(i,j)+=A(i,k)*B(k,j);
}
return C;
}
template <class VARTYPE>//умножение числа на матрицу
Matrix<VARTYPE> operator*(const double &f,const Matrix<VARTYPE> &A)
{
Matrix<VARTYPE> B=A;
for(int i=0,j;i<A.m;i++)
for(j=0;j<A.n;j++)
B(i,j)*=f;
return B;
}
template <class VARTYPE>// умножение матрицы на число
Matrix<VARTYPE> operator*(const Matrix<VARTYPE> &A, const double &f)
{
Matrix<VARTYPE> B=A;
for(int i=0,j;i<A.m;i++)
for(j=0;j<A.n;j++)
B(i,j)*=f;
return B;
}
template <class VARTYPE>
Matrix<VARTYPE>& Matrix<VARTYPE>::newsize(dim M, dim N)
{ delete [] matr;
m=M;
n=N;
if (N && M) { matr=new VARTYPE[m*n];
if (!matr) ERROR_MATRIX(1);
setmem(matr,sizeof(VARTYPE)*m*n,0); }
else { m=n=0; matr=(VARTYPE*)0; }
return *this;
}
template <class VARTYPE>
ostream& operator<<(ostream &out,Matrix<VARTYPE> &A)
{ for(int i=0,j;i<A.size_row();i++)
{ for(j=0;j<A.size_col();j++)
out << A(i,j)<< " ";
out<<endl;
}
return out;
}
template <class VARTYPE>
int operator>>(istream &inp,Matrix<VARTYPE> &A)
{ for(int i=0,j;i<A.size_row();i++)
for(j=0;j<A.size_col();j++) if( !(inp>>A(i,j)) ) return 1;
return 0;
}
template <class VARTYPE>
void Matrix<VARTYPE>::swap_line(dim L1, dim L2)
{
if (L1==L2)
return;
double b;
for(int j=0;j<n;j++)
{
b=(*this)(L1,j);
(*this)(L1,j)=(*this)(L2,j);
(*this)(L2,j)=b;
}
}
template <class VARTYPE>
void Matrix<VARTYPE>::swap_column(dim C1, dim C2)
{
if (C1==C2)
return;
double b;
for(int i=0;i<m;i++)
{
b=(*this)(i,C1);
(*this)(i,C1)=(*this)(i,C2);
(*this)(i,C2)=b;
}
}
template <class VARTYPE>
dim Matrix<VARTYPE>::read(ifstream &finp)
{ (finp.get(m)).get(n); delete []matr; matr=new VARTYPE[m*n];
if(!matr) ERROR_MATRIX(1);
setmem(matr,sizeof(VARTYPE)*m*n,0);
finp.read((char *)matr,sizeof(VARTYPE)*m*n); return finp.fail();
}
template <class VARTYPE>
dim Matrix<VARTYPE>::write(ofstream &fout)
{ (fout.put(m)).put(n);
(fout.write((char *)matr,sizeof(VARTYPE)*m*n))<<flush; return fout.fail();
}
template <class VARTYPE>
VARTYPE operator%(const Matrix<VARTYPE> &A, const Matrix<VARTYPE>&B)
{
if(A.n!=1 || B.n!=1) A.ERROR_MATRIX(9);
if(A.m!=B.m) A.ERROR_MATRIX(0);
VARTYPE scalarmul = 0;
for(int i=0; i<A.m; i++)
scalarmul = scalarmul+A(i)*B(i);
return scalarmul;
}
template <class VARTYPE>
void Matrix<VARTYPE>::ERROR_MATRIX(dim E) const
{ static char *message[] = {
"Матрицы должны иметь одинаковую размерность",//0
"Не выделена память!",//1
"Матрицы не согласованы для умножения",//2
"Степень должна быть больше нуля или -1",//3
"Матрица должна быть квадратной",//4
"Нулевой ведущий элемент в преобразовании Гаусса",//5
"Вставка невозможна из-за перекрытия базовой матрицы",//6
"Извлекаемая матрица выходит за границы базовой",//7
"Выход за границы. Попытка доступа к несущ. элементу",//8
"Это не вектор!"};//9
cerr<<"ERROR: "<< message[E] << endl; exit(1);
}
Демонстративно - тестирующая программа:
#include <conio.h>