//------------------------------------------------------------------------------

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#pragma hdrstop

//------------------------------------------------------------------------------

// Структура комплексного числа
//------------------------------------------------------------------------------
struct Complex
{
  double re, im;
  Complex();
  Complex(double x, double y);
  Complex &operator = (Complex &);
  Complex operator * (Complex &);
  Complex &operator += (Complex);
  Complex &operator *= (Complex);
  bool operator > (Complex &);
  bool operator == (Complex &);
  bool operator != (Complex &);
};

// Конструкторы
Complex::Complex()
{
  re = im = NULL;
};

Complex::Complex(double x, double y)
{
  re = x;
  im = y;
};

// Оператор присваивания
Complex &Complex::operator = (Complex &arg2)
{
  re = arg2.re;
  im = arg2.im;
  return *this;
};

// Умножение
Complex Complex::operator * (Complex &arg2)
{
  Complex tmp;
  tmp.re = re * arg2.re - im * arg2.im;
  tmp.im = re * arg2.im + im * arg2.re;
  return(tmp);
};

// Сложение и присваивание
Complex &Complex::operator += (Complex arg2)
{
  re += arg2.re;
  im += arg2.im;
  return *this;
};

// Умножение и присваивание
Complex &Complex::operator *= (Complex arg2)
{
  re = re * arg2.re - im * arg2.im;
  im = re * arg2.im + im * arg2.re;
  return *this;
};

// Оператор сравнения "больше"
bool Complex::operator > (Complex &arg2)
{
return((re * re + im * im) > (arg2.re * arg2.re + arg2.im * arg2.im));
};

// Оператор сравнения "равно"
bool Complex::operator == (Complex &arg2)
{
  return ((re == arg2.re) && (im == arg2.im));
};

// Оператор сравнения "не равно"
bool Complex::operator != (Complex &arg2)
{
  return ((re != arg2.re) || (im != arg2.im));
};

// Оператор ввода
istream& operator >> (istream &arg1, Complex &arg2)
{
  cout << "real: ";
  cin >> arg2.re;
  cout << "imaginary: ";
  cin >> arg2.im;
  return arg1;
};

// Оператор вывода
ostream& operator << (ostream &arg1, Complex &arg2)
{
  return arg1 << "(" << arg2.re << ((arg2.im < 0)?"" : "+") << arg2.im << "i)";
};

// Вспомогательная функция
//------------------------------------------------------------------------------
template <class TVal> void Rand(TVal *i)
{
  *i = (random(20)-10)/10.0;
};

// Вспомогательная функция для класса Complex
void Rand(Complex *i)
{
  double x,y;
  Rand(&x);
  Rand(&y);
  if (i == NULL) {i = new Complex(x, y);}
  i->re = x;
  i->im = y;
};

// Описание шаблона класса Matrix
//------------------------------------------------------------------------------
template <class TMatr> class Matrix
{
private:
  int Size;
  TMatr **Buf;
  int CoordTest(int i, int j){
  if ((i >= 0) && (i < Size) && (j >= 0) && (j < Size)) return 1;
  else return 0;}
public:
  Matrix();
  Matrix(int tSize);
  ~Matrix();
  // Методы получения информации из матрицы
  int GetLength(); // Получение размера матрицы
  TMatr GetVal(int i, int j); // Получить значение элемента матрицы
  void OutputMatr(); // Вывести на дисплей список значений матрицы
  // Методы добавление информации в матрицу
  void SetVal(int i, int j, TMatr val); // Присвоить новое значение элементу матрицы
  void InputMatr(); // Последовательный ввод всех значений массива с клавиатуры
  void RandomMatr(); // Заполнение массива случайными значениями
  void Add(Matrix&); // Сложение матриц
  void Mul(TMatr*); // Запись в массив произведения положительных элементов столбцов
  Matrix<TMatr> &operator = (Matrix<TMatr>&);
  bool operator > (Matrix<TMatr>&);
  // Оператор вывода
  friend ostream& operator << (ostream &arg1, Matrix<TMatr> &arg2)
  {
  for (int i=0; i < arg2.Size; i++)
    {
    for (int j=0; j < arg2.Size; j++)
      arg1 << arg2.Buf[i][j] << "  ";
    arg1 << endl;
    }
  return(arg1);
  }
};

// Реализация методов шаблона класса Matrix
//------------------------------------------------------------------------------

template<class TMatr> Matrix<TMatr>::Matrix(){
Buf = NULL;
Size = 0;}

template<class TMatr> Matrix<TMatr>::Matrix(int tSize){
Size = tSize;
Buf = new TMatr *[Size];
for (int i=0; i < Size; i++)
  Buf[i] = new TMatr[Size];}

template<class TMatr> Matrix<TMatr>::~Matrix(){
if (Buf != NULL){
  for (int n = 0; n < Size; n++)
    delete [] Buf[n];
  delete [] Buf;}}

template<class TMatr> int Matrix<TMatr>::GetLength(){
  return Size;}

template<class TMatr> TMatr Matrix<TMatr>::GetVal(int i, int j){
  if (CoordTest(i,j)) return Buf[i][j];
  else return 0;}

template<class TMatr> void Matrix<TMatr>::OutputMatr(){
  for (int i=0; i < Size; i++){
    for (int j=0; j < Size; j++){
      cout << Buf[i][j] << "  ";}
    cout << "\n";}}

template<class TMatr> void Matrix<TMatr>::SetVal(int i, int j, TMatr val){
  if (CoordTest(i,j)) Buf[i][j]=val;}

template<class TMatr> void Matrix<TMatr>::InputMatr(){
  for (int i=0; i < Size; i++)
    for (int j=0; j < Size; j++){
    cout << "Input [" << i << "][" << j << "]: ";
    cin >> Buf[i][j];}}

template<class TMatr> void Matrix<TMatr>::RandomMatr(){
  for (int i=0; i < Size; i++){
    for (int j=0; j < Size; j++)
      Rand(&Buf[i][j]);}}

template<class TMatr> void Matrix<TMatr>::Add(Matrix &arg2)
{
if (Size != arg2.Size) return;
for (int i = 0; i < Size; i++)
  for (int j = 0; j < Size; j++)
    Buf[i][j] += arg2.Buf[i][j];
};

template<class TMatr> void Matrix<TMatr>::Mul(TMatr* arr)
{
for (int j = 0; j < Size; j++)
  {
  arr[j] = 1;
  for (int i = 0; i < Size; i++)
    if (Buf[i][j] > 0) arr[j] *= Buf[i][j];
  }
};

template<class TMatr>
  Matrix<TMatr> &Matrix<TMatr>::operator = (Matrix<TMatr>& arg2)
{
if (Buf != NULL)
  {
  for (int n = 0; n < Size; n++)
    delete [] Buf[n];
  delete [] Buf;
  }
Size = arg2.Size;
Buf = new TMatr *[Size];
for (int i=0; i < Size; i++)
  Buf[i] = new TMatr[Size];
for (int i = 0; i < Size; i++)
  for (int j = 0; j < Size; j++)
    Buf[i][j] = arg2.Buf[i][j];
return(*this);
};

template<class TMatr> bool Matrix<TMatr>::operator > (Matrix<TMatr>& arg2)
{
TMatr s1 = Buf[0][0] * Buf[0][0];
TMatr s2 = arg2.Buf[0][0] * arg2.Buf[0][0];
for (int n = 1; n < Size; n++)
  s1 += Buf[n][n] * Buf[n][n];
for (int n = 1; n < arg2.Size; n++)
  s2 += arg2.Buf[n][n] * arg2.Buf[n][n];
return(s1 > s2);
};

// Шаблон класса Vector
//------------------------------------------------------------------------------
template <class Element>
class Vector
{
private:
  int size;
  Element *array;
public:
  Vector();
  Vector(int sz);
  ~Vector();
  void Sort();
  void Print();
  Element& operator [] (int i);
  Vector<Element>& operator = (Vector<Element> &arg2);
  bool operator < (Vector<Element> &arg2);
};

// Конструктор по умолчанию
template<class Element> Vector<Element>::Vector()
{
  size = 0;
  array = NULL;
};

// Конструктор с параметром размера массива
template<class Element> Vector<Element>::Vector(int sz)
{
  size = sz;
  array = new Element[size];
};

// Деструктор
template<class Element> Vector<Element>::~Vector()
{
if(array != NULL) delete [] array;
};

// Сортировка массива
template<class Element> void Vector<Element>::Sort()
{
for(int i=0; i < size-1; i++)
  for(int j = i; j < size-1; j++)
    if(array[j] > array[j+1])
      {
      Element *e = new Element;
      *e = array[j];
      array[j] = array[j+1];
      array[j+1] = *e;
      delete e;
      }
};

// Вывод на дисплей
template<class Element> void Vector<Element>::Print()
{
for(int i=0; i<size; i++)
  {cout << "[" << i << "]=" << endl << array[i];}
};

// Перегрузка оператора "[]"
template<class Element> Element& Vector<Element>::operator [] (int i)
{
return array[i];
};

// Перегрузка оператора "="
template<class Element>
  Vector<Element>& Vector<Element>::operator = (Vector<Element> &arg2)
{
if(array != NULL) {delete [] array;}
size = arg2.size;
array = new Element[size];
for(int i=0; i<size; i++)
  array[i] = arg2.array[i];
return(*this);
};

// Перегрузка оператора "<"
template<class Element> bool Vector<Element>::operator < (Vector<Element> &arg2)
{
int minSize = size < arg2.size ? size : arg2.size;
for(int i = 0; i < minSize; i++)
  {
  if((*this)[i] > arg2[i]){return(true);}
  }
return(false);
};

// Функции для демонстрации шаблона Vector, параметризованного шаблоном TList
//------------------------------------------------------------------------------
template <class TVal> void TestVector(int v1, int v2, int s)
{
clrscr();
cout << "Test object Vector:" << endl;
Vector<Matrix<TVal> > vect1(v1), vect2(v2);
Matrix<TVal> TmpMatr(s);
// Заполняем Vect1
for (int n = 0; n < v1; ++n)
  {
  vect1[n] = TmpMatr;
  vect1[n].RandomMatr();
  }
cout << "vect1: " << endl;
vect1.Print();
cout << endl;
// Заполняем Vect2
for (int n = 0; n < v2; ++n)
  {
  vect2[n] = TmpMatr;
  vect2[n].RandomMatr();
  }
cout << "vect2: " << endl;
vect2.Print();
cout << endl;
// Проверка перегруженного оператора сравнения
cout << "vect1 < vect2 = " << (vect1 < vect2) << endl << endl;
vect1 = vect2;
cout << "vect1 = vect2" << endl << endl;
vect1.Sort();
cout << "Sorted array vect1: " << endl;
vect1.Print();
cout << endl << "Press any key..";
getch();
clrscr();
};

#pragma argsused
// Головная функция
//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TestVector<Complex>(4, 5, 4);
return(0);
};
//------------------------------------------------------------------------------