Пример 22. Реализовать шаблон итератора для шаблона класса «Ли- нейный односвязный список». Предположим, что уже имеется шаблон класса линейный односвяз- ный список из примера 21. Необходимо только добавить в него методы, возвращающие итераторы на начало и конец списка. template class listIterator; template class list{
134 private: node* first; node* last; error err; public: listIterator list::begin() const; listIterator list::end() const; }; В шаблоне итератора для шаблона линейного односвязного списка определены: операция доступа к элементу, префиксная операция инкре- мента и две операции сравнения итераторов. Реализация шаблона итерато- ра аналогична реализации итератора из примера 16. template class listIterator { public: class Error { public: void what(){ cout << "Iterator error" << endl; } }; private: const list *collection; node *cur; public: listIterator(const list *s, node *e) : collection(s), cur(e){} T operator *(){ if (cur) return cur->data; else throw Error(); } listIterator operator++(); //префиксный ++ bool operator == (const listIterator &ri) const; bool operator != (const listIterator &ri) const; }; template listIterator listIterator:: operator++() { if (cur) { cur = cur->next; return *this; }
135 else throw Error(); } template bool listIterator:: operator==(const listIterator &ri) const { return ((collection == ri.collection) && (cur == ri.cur)); } template bool listIterator:: operator!=(const listIterator &ri) const { return !(*this == ri); } template listIterator list::begin() const { return listIterator(this, first); } template listIterator list::end() const { listIterator iter(this, nullptr); return iter; } Пример 23. Создать шаблон класса matrix для представления мат- рицы как вектора, элементами которого являются векторы. На основе класса myvector из примера 8 создадим шаблон класса myvector. template class myvector { private: int size; T * vect; public: myvector(int s = 1): size(s){ vect = new T[s]; } myvector(const myvector & v): size(v.size){ vect = new T[v.size]; for (int i = 0; i }
136 myvector(myvector&& v){ size = v.size; vect= v.vect; v.vect = nullptr; } myvector(){ if (vect != nullptr) delete[] vect; } T& operator [] (int i){ return vect[i]; } T operator [] (int i) const { return vect[i]; } myvector& operator= (const myvector &v){ if (&v != this) { delete[] vect; vect = new T[v.size]; for (int i = 0; i } return *this; } myvector& operator=(myvector&& v){ if (vect != nullptr) delete[] vect; size = v.size; vect = v.vect; v.vect = nullptr; return *this; } myvector operator+(const myvector& v){ if (size == v.size) { myvector v1(size); for (int i = 0; i < size; ++i) v1[i] = vect[i] + v[i]; return v1; } return *this;//лучше исключение использовать } };
137 Попробуем объявить матрицу как вектор векторов. myvector > m(3); Обратим внимание, что можно задать только одну размерность — количество строк, поскольку негде указать количество столбцов. Это свя- зано с тем, что myvector — это параметр типа для шаблонного класса myvector> При этом для каждого элемента m[i] будет вызван конструктор без параметров, в нашей реализации для него задано значение размера массива по умолчанию 1. Чтобы изменить количество столбцов в матрице, необходимо для ка- ждой строки выполнить функцию изменения размера resize. Добавим её в шаблон класса myvector. template class myvector { private: int size; T * vect; public: void resize(int n){ T* newVect = new T[n]; int sz = (n < size) ? n: size; for (int i = 0; i } }; Используем эту функцию в конструкторе шаблона класса матрицы на базе шаблона класса вектора. template class matrix{ int rows; myvector> mdata; public: matrix(int m, int n): rows(n), mdata(m){ for (int i = 0; i < m; i++)
138 mdata[i].resize(n); } }; Обратим внимание на то, что вызывать конструктор mdata(m) в те- ле конструктора matrix уже поздно (уже отработает конструктор по умолчанию), а при объявлении еще рано, поэтому конструктор необходимо вызывать в списке инициализации. Деструктор для данного класса писать не надо, т.к. достаточно сгене- рированного деструктора по умолчанию matrix(){}. Поскольку дест- руктор по умолчанию вызывает деструкторы для всех полей класса, то бу- дет вызван деструктор шаблона класса myvector >. Конструктор копии и operator= для шаблона класса matrix также сгенерируются автоматически и будут работать правильно. Если в классе есть подобъект, который берёт на себя функции по вы- делению и освобождению динамической памяти, то определять конструк- тор копии и operator= не нужно. Они необходимы, только если непо- средственно в конструкторе данного класса выделяется динамическая па- мять, а в деструкторе возвращается. Автоматически сгенерированный конструктор копии вызывает кон- структоры копий для всех своих полей. Автоматически сгенерированная операция присваивания вызывает операции присваивания для всех своих полей. Например, сгенерированный конструктор копии будет выглядеть так: matrix(const matrix & mm): mdata(mm.mdata) {} Доступ к элементу матрицы по индексам можно реализовать двумя способами.
139 Первый способ предполагает перегрузку операции индексации для матрицы с возвращением вектора (по номеру строки). Элемент из этой строки возвращается перегруженной для вектора операцией индексации. myvector& operator [] (int i) { return mdata[i]; } myvector operator [] (int i)const { return mdata[i]; } Второй способ предполагает перегрузку операции вызова функции() с двумя параметрами. T& operator()(int i, int j){ return mdata[i][j]; } T operator() (int i, int j) const { return mdata[i][j]; }
140 ЛИТЕРАТУРА 1. Дейтел Х. М., Дейтел П. Дж. Как программировать на С++. – М.: ЗАО «Издательство БИНОМ», 2000. – 1024 с. 2. Демяненко Я.М., Чердынцева М.И. Методы процедурного програм- мирования в С++. – Ростов-на-Дону: Издательство Южного феде- рального университета, 2014. – 207 с. 3. Кениг Эндрю, Му Барбара. Эффективное программирование на С++. Практическое программирование на примерах. – М.: Издательский дом «Вильямс», 2002. – 384 с. 4. Керниган Б., Ритчи Д. Язык программирования Си. – М.: Финансы и статистика, 1992. – 250 с. 5. Лишнер Рэй. С++. Справочник. – СПб.: Питер, 2005. – 907 с. 6. Русанова Я.М., Чердынцева М.И. С++ как второй язык обучения приёмам и технологиям программирования. – Ростов-на-Дону: Изда- тельство Южного федерального университета, 2010. – 200 с. 7. СкоттМайерс. Эффективное использование C++. 55 верных спосо- бов улучшить структуру и код ваших программ. – М.: ДМК Пресс, 2010 – 302 с 8. Страуструп Бьерн. Язык программирования C++. Специальное из- дание. – М.: ООО «Бином-Пресс», 2004. – 1104 с. 9. Эккель Брюс. Философия С++. Введение в стандартный С++. – СПб.: Питер, 2004. – 572 с. 10. Эккель Брюс, Эллисон Чак. Философия С++. Практическое програм- мирование. – СПб.: Питер, 2004. – 608 с. 141 11. П. Дж. Плаугер, Александр Степанов, Менг Ли, Дэвид Р. Мюссер. STL – стандартная библиотека шаблонов С++. – СПб.: БХВ- Петербург, 2004. – 656 с. 12. Дэвид Р. Мюссер, Жилмер Дж. Дердж, Атул Сейни. C++ и STL. Справочное руководство. – М.: Вильямс, 2010. – 432 с.
142 Учебное издание Демяненко Яна Михайловна Чердынцева Марина Игорьевна ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В С++ Учебное пособие Компьютерная верстка Я. М. Демяненко, М. И. Чердынцева Формат 60х841/16. Бумага офсетная. Гарнитура Times. Печать офсетная. Усл. печ. л. . Уч.-изд. л. 6,5. Тираж 50 экз. Заказ № от 2018 Издательство Южного федерального университета Отпечатано в типографии ЮФУ. 344090, г. Ростов-на-Дону, пр. Стачки, 200/1. Тел. 247-80-51.
|