Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Класс 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; просмотров: 470. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |