Министерство образования Республики Беларусь Учреждение образования «Белорусский государственный университет информатики и радиоэлектроники»
Кафедра экономической информатики
Контрольная работа №2 по курсу: «Объектно-ориентированное программирование»
Минск 2009
Задача 1 Разработать программу добавления информации в произвольное место бинарного файла. Алгоритм программы по шагам: 1. Открытие библиотек iostream, fstream, подключение класса пользовательских ошибок myExceptions.cpp. • Библиотека iostream – для доступа к функциям ввода-вывода на экран. • Библиотека fstream – для доступа к функциям ввода-вывода в файл. • Класс пользовательских ошибок myExceptions.cpp. 2. Описание класса Animal: • Закрытые поля: - Weight - хранит в себе вес животного; - itsNumberDaysAlive - хранит число прожитых животным дней; • Конструктор без параметров – инициализирует поля нолями; • Конструктор с параметрами – инициализирует поля полученными значениями; • Деструктор; • Методы доступа: - GetWeight возвращает текущее значение переменной Weight; - SetWeight устанавливает новое значение переменной Weight; - GetDaysAlive возвращает текущее значение переменной DaysAlive; - SetDaysAlive устанавливает новое значение переменной DaysAlive;
3. Описание работы метода main(): • После запуска программы ввести имя файла. Если файла с таким названием не существовало, появится ошибка открытия файла для чтения и программа продолжит работу. В обратном случае файл откроется, его содержимое выведется на экран и параллельно скопируется в массив, файл закроется. • Далее указанный файл откроется для записи (при этом если файла не было, то он создастся, а если он был, то его содержимое сотрется). После этого в файл записываются данные из массива (мы его как раз и создали, чтоб не потерялись старые данные), а затем идет цикл ввода данных с клавиатуры. Пользователь вводит значения переменных Weight и DaysAlive, затем вызывается конструктор Animal с параметрами – данными, создается объект и записывается в файл. В случае, если пользователь вводит не число, а символ – выводится сообщение об ошибке и цикл ввода запускается заново. Цикл прекращается, если пользователь введет отрицательное число. • Далее файл снова открывается для чтения, его содержимое выводится на экран и файл закрывается (Если при первом открытии файла для чтения была вызвана ошибка, то при открытии файла для записи он был создан, а затем в него добавили данные – только они и будут содержаться в файле). Пример выполнения программы:
//Вспомогательный класс животных, его объекты будут храниться в бинарном файле class Animal { public: //Конструкторы Animal():itsWeight(0), itsNumberDaysAlive(0) {} Animal(int weight, long days):itsWeight(weight), itsNumberDaysAlive(days) {} //Деструктор ~Animal(){} //Методы доступа к переменной itsWeight int GetWeight() const {return itsWeight;} void SetWeight(int weight) {itsWeight = weight;} //Методы доступа к переменной itsNumberDaysAlive long GetDaysAlive() const {return itsNumberDaysAlive;} void SetDaysAlive(long days) {itsNumberDaysAlive = days;} private: //Поля int itsWeight;//Хранит в себе вес животного long itsNumberDaysAlive;//Хранит число прожитых животным дней };
void main() { //Вводится имя файла для хранения объектов char fileName[80]; cout<<"Please enter the file name: "; cin>>fileName; Animal* masAn =new Animal [100]; Animal Anim(1,1); int i=0; //Блок открытия указанного пользователем файла для чтения(просмотр старого содержимого) //(Заодно мы копируем содержимое файла в массив, чтоб оно не потерялось последующем //открытии его для записи) try { ifstream fin(fileName); if(!fin) throw myExceptions::xNotOpenedForReading(); //Блок для вывода текущего содержимого указанного файла cout <<"\n***Current file contents:***\n\n"; while (fin.read((char *) & Anim, sizeof Anim)) { masAn[i].SetWeight(Anim.GetWeight()); masAn[i].SetDaysAlive(Anim.GetDaysAlive()); i++; cout<<"Animal weight: "<<Anim.GetWeight()<<endl; cout<<"Animal days: "<<Anim.GetDaysAlive()<<endl; cout<<endl; } cout << "\n***End of file contents.***\n"; fin.close(); } //Перехватит ошибку, если файл не может быть открыт для чтения catch (myExceptions::xNotOpenedForReading notOp) { notOp.Print(); } //Переменные int weight = 0;//Хранит вес нового животного long numberDaysAlive = 0;//Хранит количество дней жизни нового животного //Блок открытия указанного пользователем файла для записи в него объектов. //Вначале в файл будут записаны объекты из массива (те, что ранее в файле и были), //а затем - созданные из введенных пользователем значений cout << "\nOpening "<<fileName << " to writing...\n"; try { ofstream fout(fileName, ios::binary); if (!fout) throw myExceptions::xNotOpenedForWriting(); for (unsigned short j=0;j<i;j++) { Animal AnimNew =Animal(masAn[j].GetWeight(),masAn[j].GetDaysAlive()); fout.write((char*) & AnimNew, sizeof AnimNew); } //Блок для ввода данных (ввод будет продолжаться, пока пользователь не введет число <0) cout<<"Enter some data (enter number below zero to exit):\n"; char buffer[32]; cin.ignore(); while(1) { //Блок для обработки введенного массива символов (является ли он числом)для переменной weight try { cout << "Please enter the integer weight: "; cin.getline(buffer,32); cheker::isIntegerNumber(buffer); weight = atoi(buffer); if (weight >=0 ) { //Блок для обработки введенного массива символов (является ли он числом)для переменной numberDaysAlive cout<<"Please enter the long numberDaysAlive: "; cin.getline(buffer,32); cheker::isIntegerNumber(buffer); numberDaysAlive = atoi(buffer); if (numberDaysAlive >=0) { Animal AnimNew(weight,numberDaysAlive); fout.write((char*) & AnimNew, sizeof AnimNew); } else break; } else break; } //Перехватит ошибку, если ввели не число catch (myExceptions::xNotANumber notNum) { notNum.Print(); } } fout.close(); } //Перехватит ошибку, если файл не может быть открыт для записи catch (myExceptions::xNotOpenedForWriting notOp) { notOp.Print(); }
//Блок открытия указанного пользователем файла для чтения(просмотр нового содержимого) try { ifstream fin2(fileName); if(!fin2) throw myExceptions::xNotOpenedForReading(); //Блок для вывода текущего содержимого указанного файла cout <<"\n***Current file contents:***\n\n"; while (fin2.read((char *) & Anim, sizeof Anim)) { cout<<"Animal weight: "<<Anim.GetWeight()<<endl; cout<<"Animal days: "<<Anim.GetDaysAlive()<<endl; cout<<endl; } cout << "\n***End of file contents.***\n"; fin2.close(); } //Перехватит ошибку, если файл не может быть открыт для чтения catch (myExceptions::xNotOpenedForReading notOp) { notOp.Print(); } }
Листинг класса пользовательских ошибок #include <iostream.h> //using namespace std;
//Класс пользовательских ошибок class myExceptions { public: //Класс ошибки распределения памяти class xMemoryAllocationError { public: void Print() { cout <<"!!!--->Error: Memory Allocation!<---!!!\n"; } }; //Класс ошибки открытия файла для чтения class xNotOpenedForReading { public: void Print() { cout <<"!!!--->Cannot open a file for reading!<---!!!\n"; } }; //Класс ошибки открытия файла для записи class xNotOpenedForWriting { public: void Print() { cout <<"!!!--->Cannot open a file for writing!<---!!!\n"; } }; //Класс ошибки ввода числа class xNotANumber { public: void Print() { cout <<"!!!--->Is not a number!<---!!!\n"; } }; //Класс ошибки чтения данных из файла (прочтенное имеет не подходящий формат) class xNotAnAnimal { public: void Print() { cout <<"!!!--->Is not an animal! ERROR of reading file!<---!!!\n"; } }; //Класс ошибки выхода за границы массива class xOutOfRange { public: void Print() { cout <<"!!!--->Index of Array is Out Of Range!<---!!!\n"; } }; }; //Класс проверочный - содержит методы для проверки условия class cheker { public: //Вспомогательная функция, осуществляет проверку правильности ввода пользователем целого числа static void isIntegerNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-')) throw myExceptions::xNotANumber(); Buf++; } } //Вспомогательная функция, осуществляет проверку правильности ввода пользователем вещественного числа static void isDoubleNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-'||(*Buf) == '.')) throw myExceptions::xNotANumber(); Buf++; } } }; Задача 2 Реализовать шаблон класса vector, реализующий динамический массив. Используя локальную функцию класса выполнить удаление из массива наибольшего элемента. Содержимое объекта (объектов) после этого вывести на экран ( используя cout << объект; ). 1) Задачу реализовать как шаблонный класс; Блок-схема программы:
//Класс пользовательских ошибок class myExceptions { public: //Класс ошибки распределения памяти class xMemoryAllocationError { public: void Print() { cout <<"!!!--->Error: Memory Allocation!<---!!!\n"; } }; //Класс ошибки открытия файла для чтения class xNotOpenedForReading { public: void Print() { cout <<"!!!--->Cannot open a file for reading!<---!!!\n"; } }; //Класс ошибки открытия файла для записи class xNotOpenedForWriting { public: void Print() { cout <<"!!!--->Cannot open a file for writing!<---!!!\n"; } }; //Класс ошибки ввода числа class xNotANumber { public: void Print() { cout <<"!!!--->Is not a number!<---!!!\n"; } }; //Класс ошибки чтения данных из файла (прочтенное имеет не подходящий формат) class xNotAnAnimal { public: void Print() { cout <<"!!!--->Is not an animal! ERROR of reading file!<---!!!\n"; } }; //Класс ошибки выхода за границы массива class xOutOfRange { public: void Print() { cout <<"!!!--->Index of Array is Out Of Range!<---!!!\n"; } }; }; //Класс проверочный - содержит методы для проверки условия class cheker { public: //Вспомогательная функция, осуществляет проверку правильности ввода пользователем целого числа static void isIntegerNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-')) throw myExceptions::xNotANumber(); Buf++; } } //Вспомогательная функция, осуществляет проверку правильности ввода пользователем вещественного числа static void isDoubleNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-'||(*Buf) == '.')) throw myExceptions::xNotANumber(); Buf++; } } };
Листинг класса пользовательских ошибок #include <iostream.h>
//Класс пользовательских ошибок class myExceptions { public: //Класс ошибки распределения памяти class xMemoryAllocationError { public: void Print() { cout <<"!!!--->Error: Memory Allocation!<---!!!\n"; } }; //Класс ошибки открытия файла для чтения class xNotOpenedForReading { public: void Print() { cout <<"!!!--->Cannot open a file for reading!<---!!!\n"; } }; //Класс ошибки открытия файла для записи class xNotOpenedForWriting { public: void Print() { cout <<"!!!--->Cannot open a file for writing!<---!!!\n"; } }; //Класс ошибки ввода числа class xNotANumber { public: void Print() { cout <<"!!!--->Is not a number!<---!!!\n"; } }; //Класс ошибки чтения данных из файла (прочтенное имеет не подходящий формат) class xNotAnAnimal { public: void Print() { cout <<"!!!--->Is not an animal! ERROR of reading file!<---!!!\n"; } }; //Класс ошибки выхода за границы массива class xOutOfRange { public: void Print() { cout <<"!!!--->Index of Array is Out Of Range!<---!!!\n"; } }; }; //Класс проверочный - содержит методы для проверки условия class cheker { public: //Вспомогательная функция, осуществляет проверку правильности ввода пользователем целого числа static void isIntegerNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-')) throw myExceptions::xNotANumber(); Buf++; } } //Вспомогательная функция, осуществляет проверку правильности ввода пользователем вещественного числа static void isDoubleNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-'||(*Buf) == '.')) throw myExceptions::xNotANumber(); Buf++; } } };
1) Задачу реализовать как класс контейнера и итератора Пример выполнения программы:
Листинг программы: #include <iostream.h> #include <stdlib.h> #include "myExceptions.cpp" template<typename TYPE> //Шаблон класса Vector class Vector { public: //шаблон класса итератор template<typename TYPE> class Iterator { public: TYPE* nodePtr; public: //Конструктор шаблона класса итератор Iterator<TYPE>::Iterator(TYPE* node = NULL) { nodePtr = node; } //Перегрузка оператора инкремента в постфиксной форме Iterator<TYPE>& operator ++() { if(nodePtr) nodePtr = nodePtr++; return *this; } //Перегрузка оператора инкремента в префиксной форме Iterator<TYPE>& operator ++(int t ) { if(nodePtr) nodePtr = nodePtr++; return *this; } //Перегрузка оператора декремента в постфиксной форме Iterator<TYPE>& operator --() { if(nodePtr) nodePtr = nodePtr--; return *this; } //Перегрузка оператора декремента в префиксной форме Iterator<TYPE>& operator --(int t ) { if(nodePtr) nodePtr = nodePtr--; return *this; } //Перегрузка оператора разыменования TYPE operator *() { if(nodePtr) return *nodePtr; return TYPE(); } }; private: //Данные - поля TYPE * arrayNode;//Хранит массив элементов int lenght;//Хранит длину массива public: //Конструкторы Vector() { arrayNode = new TYPE [1] ; lenght = 0; } Vector(int l) { arrayNode = new TYPE [len]; lenght = len;
for (int i = 0; i<len; i++) arrayNode[i] = 0; } //Деструктор ~Vector() { if(arrayNode) delete arrayNode; } //Метод доступа к длине массива int GetLenght() { return lenght; } //Метод добавления элемента в массив Vector * Add(TYPE Data) { try { int len = this->lenght +1; TYPE * arrayNodeNew = new TYPE[len] ; for (int i=0; i<this->lenght; i++) arrayNodeNew[i]=this->arrayNode[i]; arrayNodeNew[this->lenght]=Data; if(!arrayNodeNew) throw myExceptions::xMemoryAllocationError(); delete arrayNode; arrayNode = new TYPE[len]; for (int j=0; j<len; j++) this->arrayNode[j]=arrayNodeNew[j]; lenght=len;
return this; } catch (myExceptions::xMemoryAllocationError memAll) { memAll.Print(); } return NULL; } //Перегруженный оператор << friend ostream & operator << (ostream &, Vector<TYPE> &); //Метод для получения ссылки к первому доступному узлу Iterator<TYPE> begin() { return Iterator<TYPE>(arrayNode); } //Метод для удаления максимального элемента из массива bool Delete() { int num=0; //Для хранения индекса максимального элемента for (int i=0; i<this->lenght; i++) if (arrayNode[i]>arrayNode[num]) num=i; try { int j=0; int len = this->lenght -1; TYPE * arrayNodeNew = new TYPE[len] ; if(!arrayNodeNew) throw myExceptions::xMemoryAllocationError(); //Циклы для копирования элементов, кроме максимального из текущего массива в новый for (int i=0; i<num; i++,j++) arrayNodeNew[j]=this->arrayNode[i]; for (int q=num+1; q<this->lenght; q++,j++) arrayNodeNew[j]=this->arrayNode[q]; //переопределение текущего массива delete arrayNode; arrayNode = new TYPE[len]; this->lenght=len; if(!arrayNode) throw myExceptions::xMemoryAllocationError(); //Перезапись элементов в текущий массив for (int t=0; t<len; t++) this->arrayNode[t]=arrayNodeNew[t]; return true; } //Ошибка будет перехвачена, если не выделилась память под массив (память занята) catch (myExceptions::xMemoryAllocationError memAll) { memAll.Print(); } return false; } };
void main() { //Создание массива целых чисел Vector <int> intVec; int val; char buffer[32]; //cin.ignore(); //Цикл добавления элементов в массив for(;;) { try { cout<<"What integer value to Vector? (character to stop): "; cin.getline(buffer,32); cheker::isIntegerNumber(buffer); val = atoi(buffer); intVec.Add(val); } catch (myExceptions::xNotANumber notNum) { notNum.Print(); break; } } //Вывод массива cout<<"\nVector of integer numbers:\n"; cout<<intVec; cout<<endl; //Удаление из массива максимального элемента intVec.Delete(); //Вывод массива cout<<"\nVector of integer numbers after deleting Max element:\n"; cout<<intVec; cout<<endl;
//Объявление итератора Vector<int>::Iterator<int> it; int t=0,t1; //Проверка правильности работы итератора - попытка вывода элементов по индексу cout<<"Enter index of element, which you want to be printed: "; cin>>t1; try { if (t1>=intVec.GetLenght() || t<0) throw myExceptions::xOutOfRange(); for (it=intVec.begin();t<t1;it++,t++); cout<<"Element on ["<<t<<"] place: "<<*it<<"\n"; it--; t--; if (t<intVec.GetLenght() && t>=0) cout<<"Element from left of them on place ["<<t<<"] and it is a "<<*it<<"\n"; else throw myExceptions::xOutOfRange(); it++; t++; it++; t++; if (t<intVec.GetLenght() && t>=0) cout<<"Element from right of them on place ["<<t<<"] and it is a "<<*it<<"\n"; else throw myExceptions::xOutOfRange(); } //Ошибка перехватится, если в процессе работы индекс элемента массива вышел за границы //допустимого диапазона catch (myExceptions::xOutOfRange indOut) { indOut.Print(); } }
Листинг класса пользовательских ошибок: #include <iostream.h>
//Класс пользовательских ошибок class myExceptions { public: //Класс ошибки распределения памяти class xMemoryAllocationError { public: void Print() { cout <<"!!!--->Error: Memory Allocation!<---!!!\n"; } }; //Класс ошибки открытия файла для чтения class xNotOpenedForReading { public: void Print() { cout <<"!!!--->Cannot open a file for reading!<---!!!\n"; } }; //Класс ошибки открытия файла для записи class xNotOpenedForWriting { public: void Print() { cout <<"!!!--->Cannot open a file for writing!<---!!!\n"; } }; //Класс ошибки ввода числа class xNotANumber { public: void Print() { cout <<"!!!--->Is not a number!<---!!!\n"; } }; //Класс ошибки чтения данных из файла (прочтенное имеет не подходящий формат) class xNotAnAnimal { public: void Print() { cout <<"!!!--->Is not an animal! ERROR of reading file!<---!!!\n"; } }; //Класс ошибки выхода за границы массива class xOutOfRange { public: void Print() { cout <<"!!!--->Index of Array is Out Of Range!<---!!!\n"; } }; }; //Класс проверочный - содержит методы для проверки условия class cheker { public: //Вспомогательная функция, осуществляет проверку правильности ввода пользователем целого числа static void isIntegerNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-')) throw myExceptions::xNotANumber(); Buf++; } } //Вспомогательная функция, осуществляет проверку правильности ввода пользователем вещественного числа static void isDoubleNumber(char* _Buf) { char* Buf = _Buf; while(*Buf) { if(!(((*Buf) >= '0' && (*Buf) <= '9') || (*Buf) == '-'||(*Buf) == '.')) throw myExceptions::xNotANumber(); Buf++; } } }; Диаграмма классов: