Смекни!
smekni.com

Разработка библиотечных средств (стр. 3 из 4)

Функция операции вывода 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>