Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Класс TVector с перегруженными операциями




Хотелось бы при работе с массивом, т.е. классом TVector, иметь возможность использовать операцию [] доступа к элементу массива по индексу для того, чтобы получить значение элемента массива или модифицировать его. Совсем не вредно, чтобы при этом класс проверял корректность индекса с тем, чтобы не было попыток выхода за границы массива. Ну и еще бы хотелось иметь возможность вывода значений всех элементов массива с помощью стандартного потока cout. Все это, и многое другое, действительно возможно выполнить с помощью перегрузки операций. Для того чтобы все эти мечты воплотить в жизнь, надо в объявление класса (файл TVector.h) добавить такие описания:

 

В файл реализации класса TVector.срр остается добавить реализацию функции, выполняющей перегрузку операции доступа к элементам массива по индексу:

ElemType & TVector::operator [](int Index)

if((Index>=0)&&(Index<VectorSize)) return pVec[Index];

}

 

Теперь в программе, использующей данный класс, можно использовать выражения такого вида:

TVector MyVec(3,5,-1);

cout<<MyVec;// вывод всех элементов массива

MyVec[k]=12.3;// присваивание значения к-тому элементу массива

ElemType Val= MyVec[k];// получение значения к-того элемента массива

 

Если Вы внимательно посмотрите на функцию перегрузки операции [], то у Вас, наверное, возникнет вопрос: а что функция вернет, если индекс будет вне границ массива? А неизвестно что, т.е. случайное значение, что не есть хорошо. Ну и как же быть в этом случае? Приемлемым выходом является генерация исключительной ситуации (исключения), которую может перехватить вызывающая функция. Текст функции  перегрузки операции [] можно в этом случае записать так:

ElemType & TVector::operator [](int Index)

if((Index<0)||(Index>=VectorSize)) throw "Bad index";

return pVec[Index];

}

 

В этом случае вызывающая функция может поступать таким образом:

try

{

// …

   MyVec[i]=0;

// …

}

catch(char * Mes)

{

   AfxMessageBox(Mes);

}

 

Если при вычислении выражения MyVec[i] индекс будет вне диапазона, выполнится оператор, указанный в блоке catch, т.е. в данном случае на дисплее будет показано окно с текстом "Bad index". Естественно, что в реальной программе для обработки такой ошибки надо реализовать что-то более целесообразное, чем вывод сообщения пользователю Вашей программы.



Шаблоны классов

Пример шаблона класса

Исключительно в качестве иллюстрации использования шаблона класса приведу пример очень простой реализации шаблона массива CArr (проект Vector). В чем состоит главное отличие класса CArr от класса TVector, приведенного выше? Чтобы использовать класс TVector для своего типа данных (тип элементов массива), надо переопределить тип ElemType и выполнить компиляцию этого класса для своего собственного типа данных. Если в приложении надо использовать массивы нескольких типов, то придется создавать копии класса TVector для каждого типа данных или разрабатывать какую-нибудь сложную схему использования класса. Нетрудно представить себе также весь тот кошмар, который придется пережить при необходимости обновления класса TVector. В то же время использование шаблона класса не будет требовать от Вас переопределения типов или создания разных вариантов реализации класса массив: компилятор сам сгенерирует столько классов массив с разным типом элементов, сколько понадобится. Здесь имеет место быть практически полная аналогия с использованием перегруженных функций и шаблона функций. 

 

template <class ElType, int Size>

Class CArr

{

public:

   CArr() { for(int i=0;i<Size; i++) Mas[i]=0;}

   bool Put(const ElType & Elem, int Index);

   bool Get(ElType & Elem, int Index);

   ElType operator [](int index) {return Mas[index];}

private:

   ElType Mas[Size];

};

template <class ElType, int Size>

bool CArr<ElType,Size>::Put(const ElType & Elem, int Index)

{

if (Index>=0 && Index<Size)

{

   Mas[Index]=Elem;

   return true;

}

else return false;

}

template <class ElType, int Size>

bool CArr<ElType,Size>::Get(ElType & Elem, int Index)

{

if (Index>=0 && Index<Size)

{

   Elem=Mas[Index];

   return true;

}

else return false;

}

 

Пример использования шаблона класса CArr.

 

CArr <float,5> fMas,fMas2; // 5 – максимальное число элементов массива

int i=0;

float F=1.0;

while(fMas.Put(F,i++))F+=0.5;

i=0;

cout<<"fMas : ";

while(fMas.Get(F,i++)) cout<<F<<' ';

cout<<endl;

fMas2=fMas;

cout<<"fMas2: ";

for(i=0;i<5;i++) cout<<fMas2[i]<<' ';

cout<<endl;

// fMas2[0]=-1;

cout<<"fMas2: ";

for(i=0;i<5;i++) cout<<fMas2[i]<<' ';

cout<<endl;

 

Для того чтобы можно было использовать выражение fMas2[i] в качестве левостороннего (lvalue), т.е. иметь возможность присваивать значения элементам массива с использованием перегруженной операции [], надо эту перегруженную операцию определить как возвращающую ссылку на ElType:

ElType & operator [](int index) {return Mas[index];}

 

Конечно, в данном шаблоне использован простейший способ хранения элементов массива – просто в массиве, размер которого задается при определении экземпляра класса. (Вместе с тем, этот простейший способ имеет и максимальную эффективность.) Для расширения функциональности во «взрослом» шаблоне класса надо было бы ввести многие усовершенствования:

· расширить число функций и операций, предоставляемых классом;

· реализовать контроль над индексами элементов массива;

· добавить генерацию исключений при ошибках внешней программы;

· добавить возможность автоматического выделения памяти при расширении массива и т.п.

 

Стоит отметить, что при генерации реального класса на основе шаблона генерируются только те функции, которые реально используются в программе.

Шаблон класса TVector

Все описания надо разместить в заголовочном файле

 

template <class ElemType>

class TVector

{

public:

  TVector();

  TVector(int iSize, int iGain=0, ElemType InitValue=0);

  virtual ~TVector();

  bool SetCapacity(int NewCapacity);

  bool SetElem(const ElemType &Value, int Index);

  bool GetElem(ElemType &Value, int Index) const;

  bool InsertElem(const ElemType &Value, int Index);

  bool DeleteElem(int Index);

  void AddElem(const ElemType &Value);

  int Size() const {return VectorSize;}

  int Capacity() const {return VectorCapacity;}

  bool InsertVec(TVector &SubVector, int Index);

  ElemType& operator [](int Index);

  friend ostream & operator <<(ostream &out,const TVector<ElemType> &Vec)

  {

              if(!Vec.pVec) return out;

              for(int i=0;i<Vec.VectorSize; i++)

              {

                          out.width(5); out.precision(2); out.fixed;

                          out<<Vec.pVec[i];

              }

              return out;

  }

protected:

  ElemType * pVec;

  int VectorSize, VectorCapacity, Gain;

};

template <class ElemType>

TVector<ElemType>::TVector(int iSize, int iGain, ElemType InitValue)

{

  Gain=iGain;

  if(iSize<=0)

  {

              pVec=0;

              VectorCapacity=VectorSize=0;

              return;

  }

  pVec=new ElemType [iSize];

  VectorCapacity=VectorSize=iSize;

  for(int i=0;i<VectorSize; pVec[i++]=InitValue);

}

// …

template <class ElemType>

bool TVector<ElemType>::InsertVec(TVector<ElemType> &SubVector, int Index)

{

  if((Index<0)||(Index+SubVector.Size()>VectorSize-1))

  return false;

  if(VectorSize+SubVector.Size()>VectorCapacity)

  SetCapacity(VectorSize+SubVector.Size());

  VectorSize+=SubVector.Size();

  for(int i=VectorSize-1;i>=Index; i--) pVec[i] = pVec[i-SubVector.Size()];

/*!!!*/    for(int i=Index; i<Index+SubVector.Size(); i++) pVec[i]=SubVector[i-Index];

  return true;

}

 

// и т.д.

 

Использование шаблона:

 

void Print(TVector<double> &Vec)

{

  cout<<"=========================="<<endl;

  cout<<"Vec.Capacity=="<<Vec.Capacity()<<" Vec.Size=="<<Vec.Size()<<endl;

  cout<<Vec;

  cout<<endl<<"=========================="<<endl;

}

  TVector <double> MyVec(3,5,-1.1);

  int N=5,Index,i;

  double Val=0.1;

  try

  {

              for(i=0;i<N; i++)

              {

                          MyVec.AddElem(Val);

                          Val+=1;

              }

  MyVec[-1]=0; // для проверки того, что ИС будет сгенерирована и перехвачена

  }

  catch(char * Mes)

  {

              AfxMessageBox(CString(Mes));

  }

 


 










Последнее изменение этой страницы: 2018-04-12; просмотров: 418.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...