close

Вход

Забыли?

вход по аккаунту

?

4. записка

код для вставкиСкачать

Введение
Безусловно, в современном мире основной парадигмой программирования является технология ООП. Что же это такое? Объе́ктно-ориенти́рованное, или объектное, программи́рование (в дальнейшем ООП) - парадигма программирования, в которой основными концепциями являются понятия объектов и классов.
ООП возникло в результате развития идеологии процедурного программирования, где данные и подпрограммы (процедуры, функции) их обработки формально не связаны. Для дальнейшего развития объектно-ориентированного программирования часто большое значение имеют понятия события (так называемое событийно-ориентированное программирование) и компонента (компонентное программирование, КОП).
В центре ООП находится понятие объекта. Объект - это сущность, которой можно посылать сообщения, и которая может на них реагировать, используя свои данные. Объект - это экземпляр класса. Данные объекта скрыты от остальной программы. Тема данной курсовой работы выбрана таким образом, что в ходе реализации программы будут задействованы и изучены основные принципы ООП.
1. Теоретическая часть
1.1 Шаблоны
Возникают случаи, когда мы хотим использовать класс, позволяющий удобно работать сразу с несколькими типами. Но тогда придётся писать отдельные реализации этих классов для каждого типа. Они будут похожи: отличие будет только в имени типа. Очевидно, что это неудобно и плохо: происходит дублирование кода; в случае, когда необходимо несколько реализаций, придётся включать несколько заголовочных файлов; может возникнуть путаница.
По мере того как программы становятся более сложными, возможны ситуации, когда потребуются подобные функции, выполняющие одни и те же операции, но с разными типами данных. Шаблон функции позволяет программам определять общую, или типонезависимую, функцию. Когда в программе требуется использовать функцию для определенного типа, например int или double, она указывает прототип функции, который использует имя шаблона функции и типы возвращаемого значения и параметров. В процессе компиляции C++ создаст соответствующую функцию. Создавая шаблоны, уменьшается количество функций, которые должны кодировать самостоятельно, а программы могут использовать одно и то же имя для функций, выполняющих определенную операцию, независимо от возвращаемого функцией значения и типов параметров.
1.2 Бинарный файл
Двоичный (бинарный) файл - в широком смысле: последовательность произвольных байтов. Название связано с тем, что байты состоят из бит, то есть двоичных (англ. binary) цифр.
В узком смысле слова двоичные файлы противопоставляются текстовым файлам. При этом с точки зрения технической реализации на уровне аппаратуры, текстовые файлы являются частным случаем двоичных файлов, и, таким образом, в широком значении слова под определение "двоичный файл" подходит любой файл.
2. Структурное описание программы
Основной структурой в программе является шаблон класса List. Интерфейс шаблона:
template <typename T>
struct Elem
{
T * data;
Elem<T>* next, * prev;
};
template <typename T>
class List
{
vector< Elem<T>* > TenElems;
Elem<T>* Head, * Tail;
int Count;
void RecomputeTens();
public:
List();
List(const List&);
~List();
int GetCount();
Elem<T>* GetElem(int);
void DelAll();
void Del(int);
void Del();
void AddTail();
void AddTail(T*);
void AddHead(T*);
void AddHead();
void Insert();
void Print();
void Print(int pos);
void SaveBin(const char *name);
void LoadBin(const char *name);
List& operator = (const List&);
};
Описание использованных член-данных шаблона: template <typename T>, struct Elem - структура шаблона, содержащая указатель на объект T * data, и на следующий и предыдущий элементы Elem<T>* next, * prev.
Elem<T>* Head, * Tail - это член-данные шаблона, которые содержат указатели на голову и хвост.
int Count - число элементов в списке.
vector< Elem<T>* > TenElems - шаблон, содержащий ссылки на каждый 10-ый элемент функции.
3. Функциональное описание
3.1 Добавляем элемент в конец списка: AddTail(T*). Выделяется память на элемент списка и на объект. Определяет указатели нового элемента.
template<typenameT>
void List<T>::AddTail(T *n)
{
Elem<T> * temp = new Elem<T>;
temp->next = 0;
temp->data = new T(*n);
temp->prev = Tail;
if(Tail != 0)
Tail->next = temp;
if(Count == 0)
Head = Tail = temp;
else
Tail = temp;
Count++;
if (Count % 10 == 0)
TenElems.push_back(temp);
}
3.2 Добавление элемента в начало списка: AddHead(T*).
template<typename T>
void List<T>::AddHead(T *n)
{
Elem<T> * temp = new Elem<T>;
temp->prev = 0;
temp->data = new T(*n);
temp->next = Head;
if(Head != 0)
Head->prev = temp;
if(Count == 0)
Head = Tail = temp;
else
Head = temp;
Count++;
if (Count % 10 == 0)
TenElems.push_back(temp);
}
3.3 Удаление элемента из списка по заданному порядковому номеру: voidDel(int). Функция выводит ошибку, если указан недопустимый порядковый номер. Иначе удаляет элемент с заданным порядковым номером и пересчитывает указатели на каждый 10-ый элемент. Счетчик элементов уменьшается на 1:
template<typename T>
void List<T>::Del(int n)
{
if(n < 1 || n > Count)
{
cout<< "Incorrect position !!!\n";
return;
}
inti = 1;
Elem<T> * Del = Head;
int tens = n / 10;
if (tens > 0) {
Del = TenElems[tens - 1];
n -= tens * 10;
}
while(i< n)
{
Del = Del->next;
i++;
}
Elem<T> * PrevDel = Del->prev;
Elem<T> * AfterDel = Del->next;
if(PrevDel != 0 && Count != 1)
PrevDel->next = AfterDel;
if(AfterDel != 0 && Count != 1)
AfterDel->prev = PrevDel;
if(n == 1)
Head = AfterDel;
if(n == Count)
Tail = PrevDel;
RecomputeTens();
Count--;
delete Del->data;
delete Del;
}
3.4 Вывод элемента на экран: voidPrint(intpos). Находит заданную позицию и выводит на экран. Так же задан метод voidPrint(), выводящий все элементы списка на экран.
template<typename T>
void List<T>::Print()
{
if(Count != 0)
{
Elem<T> * temp = Head;
while(temp != 0)
{
cout<< *temp->data<< ' ';
temp = temp->next;
}
}
cout<<endl;
} 3.5 Сохранение в бинарный файл: SaveBin(constchar *name). Получает имя файла, открывает файловый поток вывода в бинарном режиме. Сначала в файл записывается количество элементов, затем сами элементы. Для строки так же записывается ее длина. Для записи используется библиотека IOStream.
template<classT>
void List<T>::SaveBin(const char *name) {
if (Head==NULL)
{
cout<<"\nEmpty List\n"; return;
}
ofstream File(name,ios::binary); File.write((char *)&Count,sizeof(int)); for(Elem<T> *pt = Head; pt != NULL; pt = pt->next) {
if (pt->data == 0) {
T nul=0;
File.write((char *)&nul, sizeof(T)); continue;
}
File.write((char*)pt->data, sizeof(T));
}
cout<< "Saved on file ''" << name << "''\n\n";
} 3.6 Загрузка из бинарного файла: LoadBin(const char *name).
Этот метод в целом симметричен методу save. Так же используется библиотека IOStream. Очищает уже существующий в памяти список, открывает файл, считывает количество элементов и каждый элемент - воссоздает записанный список.
void List<T>::LoadBin(const char *name)
{
ifstream File(name, ios::binary); if (!File) {
cout<<"Couldn't be open"; return;
} if (Count != 0)
DelAll(); int n;
Elem<T> *pt = new Elem<T>;
Elem<T> *firstpt = pt; File.read((char *)&Count, sizeof(int)); for (int n = Count ; n > 0; n--) {
T tmp;
pt->next=NULL;
File.read((char*)&tmp, sizeof(T));
if (tmp == 0) pt->data = NULL;
else
pt->data = new T(tmp); if (n != 1)
{
Elem<T> *temppt = new Elem<T>;
pt->next = temppt;
pt->next->prev = pt;
pt = temppt;
}
}
Head = firstpt;
Tail = pt;
RecomputeTens();
cout<< "Load from file ''" << name << "''\n\n";
}
4. Руководство пользователя и тестирование
В самом начале работы программы пользователю предлагается указать тип данных списка, который он хочет ввести.
Протестируем нашу программу на типе данных int.
Предположим, что пользователь ввел 1, т.е. тип данных int.
Первоначально список содержит NULL, для того чтобы добавить в него элементы, пользователь может воспользоваться несколькими вариантами ввода:
1 - добавление в конец списка, нажав 2
2 - добавление по логическому номеру (ключу), нажав 3 Для начала рассмотрим операцию добавление по логическому номеру, нажав на цифру 3, пользователю предлагается ввести позицию и сам элемент соответственно Теперь рассмотрим операцию добавления в конец списка, соответственно нажимаем 2, пользователю предлагается ввести элемент, который будет вставлен в конец списка.
Теперь, когда список сформирован, мы можем его вывести на экран, соответственно, вызвав функцию вывода данных из списка на печать, нажав 1:
А так же есть функции сохранения, записи в бинарный файл, удаление по логическому номеру и получение следующего элемента по логическому номеру.
Заключение
Разработанная программа полностью соответствует полученному заданию.
Обработаны случаи неверного ввода данных пользователем.
При разработке были использованы основные принципы объектно-ориентированного программирования.
Приложение
main.cpp
include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include "list.h"
using namespace std;
template <typename T>
void PerformTests(const char *name);
void Start();
int main()
{
setlocale(LC_ALL,"rus");
while(1)
{
char key;
cout<<"Введите тип данных для работы :\n";
cout<<"1 - int\n";
cout<<"2 - double\n";
cout<<"3 - char *\n";
cout<<"q - Выход\n";
cout<<"Введите дйствие : ";
cin>>key;
switch (key)
{
case '1':
PerformTests<int>("intdata.bin");
break;
case '2':
PerformTests<double>("doubledata.bin");
break;
case '3':
PerformTests<string>("stringdata.bin");
break;
case 'q': return 0; break;
default: cout<<"incorrect choice\n"; break;
}
cout<<endl;
}
}
void PrintMenu() {
cout<<"Menu: \n";
cout<<"1 - ввод данных из списка на экран \n";
cout<<"2 - добавление в конец списка\n";
cout<<"3 - добавление по логическому номеру \n";
cout<<"4 - извлечение по логическому номеру \n";
cout<<"5 - удаление по логическому номеру \n";
cout<<"6 - получение следующего элемента по логическому номеру \n";
cout<<"7 - получение предыдущего элемента по логическому номеру \n";
cout<<"8 - сохранение в бинарный файл\n";
cout<<"9 - загрузка в бинарный файл'a\n";
cout<<"0 - изменяем тип данных\n";
cout<<"q - Выход\n";
cout<<"Ваш выбор : ";
}
template <typename T>
void PerformTests(const char *name)
{
bool ChangeType=false; char key;
int inpK; List<T> *p = new List<T>(); while(1)
{
try {
PrintMenu(); //вывод меню
cin>>key;
cout<<endl;
switch(key)
{
case '1': p->Print(); break;
case '2':
p->AddTail(); break;
case '3':
p->Insert(); break;
case '4':
cout<<"Введите номер для извлечения: ";
cin>>inpK;
p->Print(inpK); break;
case '5':
cout<<"Введите номер для удаления: ";
cin>>inpK;
p->Del(inpK); break;
case '6':
cout<<"Введите номер для извлечения : ";
cin>>inpK;
p->Print(inpK+1); break;
case '7':
cout<<"Введите номер для извлечения: ";
cin>>inpK;
p->Print(inpK-1); break;
case '8':
p->SaveBin(name); break;
case '9':
p->LoadBin(name); break;
case '0':
ChangeType=true; break;
case 'q': exit(0);
default : exit(0);
}
}
catch (...)
{
cout<<"Неизвестная ошибка\n\n";
}
if (ChangeType)
break;
}
delete p;
}
list.h
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template <typename T>
struct Elem
{
T * data;
Elem<T>* next, * prev;
};
template <typename T>
class List
{
vector< Elem<T>* > TenElems;
Elem<T>* Head, * Tail;
int Count;
void RecomputeTens();
public:
List();
List(const List&);
~List();
int GetCount();
Elem<T>* GetElem(int);
void DelAll();
void Del(int);
void Del();
void AddTail();
void AddTail(T*);
void AddHead(T*);
void AddHead();
void Insert();
void Print();
void Print(int pos);
void SaveBin(const char *name);
void LoadBin(const char *name);
List& operator = (const List&);
};
template <typename T>
List<T>::List()
{
Head = Tail = NULL;
Count = 0;
}
template <typename T>
List<T>::List(const List & L)
{
Head = Tail = 0;
Count = 0;
Elem<T> * temp = L.Head;
while(temp != 0)
{
AddTail(temp->data);
temp = temp->next;
}
}
template <typename T>
List<T>::~List()
{
DelAll();
}
template <typename T>
Elem<T>* List<T>::GetElem(int pos)
{
Elem<T> *temp = Head;
if(pos < 1 || pos > Count)
{
cout << "Неправильная позиция !!!\n";
return;
}
int tens = pos / 10;
if (tens > 0) {
temp = TenElems[tens - 1];
pos -= tens * 10;
}
int i = 1;
while(i < pos && temp != 0)
{
temp = temp->next;
i++;
}
if(temp == 0)
return 0;
else
return temp;
}
template <typename T>
void List<T>::AddHead()
{
T elem;
cout << "Введите новый элемент: ";
cin >> elem;
AddHead(&elem);
}
template <typename T>
void List<T>::AddHead(T *n)
{
Elem<T> * temp = new Elem<T>;
temp->prev = 0;
temp->data = new T(*n);
temp->next = Head;
if(Head != 0)
Head->prev = temp;
if(Count == 0)
Head = Tail = temp;
else
Head = temp;
Count++;
if (Count % 10 == 0)
TenElems.push_back(temp);
}
template <typename T>
void List<T>::AddTail()
{
T elem;
cout << "Введите новый элемент: ";
cin >> elem;
AddTail(&elem);
}
template <typename T>
void List<T>::AddTail(T *n)
{
Elem<T> * temp = new Elem<T>;
temp->next = 0;
temp->data = new T(*n);
temp->prev = Tail;
if(Tail != 0)
Tail->next = temp;
if(Count == 0)
Head = Tail = temp;
else
Tail = temp;
Count++;
if (Count % 10 == 0)
TenElems.push_back(temp);
}
template <typename T>
void List<T>::Del()
{
int n;
cout << "Входные позиции: ";
cin >> n;
Del(n);
}
template <typename T>
void List<T>::Del(int n)
{
if(n < 1 || n > Count)
{
cout << "Неправильная позиция !!!\n";
return;
}
int i = 1;
Elem<T> * Del = Head;
int tens = n / 10;
if (tens > 0) {
Del = TenElems[tens - 1];
n -= tens * 10;
}
while(i < n)
{
Del = Del->next;
i++;
}
Elem<T> * PrevDel = Del->prev;
Elem<T> * AfterDel = Del->next;
if(PrevDel != 0 && Count != 1)
PrevDel->next = AfterDel;
if(AfterDel != 0 && Count != 1)
AfterDel->prev = PrevDel;
if(n == 1)
Head = AfterDel;
if(n == Count)
Tail = PrevDel;
RecomputeTens();
Count--;
delete Del->data;
delete Del;
}
template <typename T>
void List<T>::RecomputeTens() {
if (Count > 10 && TenElems.empty()) {
int i = 1;
for (Elem<T>* elem = Head; elem != NULL; elem = elem->next, i++)
if (i % 10 == 0)
TenElems.push_back(elem);
return;
}
for (int i = 0; i < TenElems.size(); i++) {
Elem<T>* elem = TenElems[i];
if (elem == Tail)
TenElems.resize(TenElems.size() - 1);
else
TenElems[i] = elem->next;
}
}
template <typename T>
void List<T>::Print(int pos)
{
if(pos < 1 || pos > Count)
{
cout << "Неправильная позиция !!!\n";
return;
}
Elem<T> * temp;
if(pos <= Count / 2)
{
temp = Head;
int i = 1;
int tens = pos / 10;
if (tens > 0) {
temp = TenElems[tens - 1];
pos -= tens * 10;
}
while(i < pos)
{
temp = temp->next;
i++;
}
}
else
{
temp = Tail;
int i = 1;
int tens = pos / 10;
if (tens > 0 && tens < TenElems.size()) {
temp = TenElems[tens];
pos += Count - (tens + 1) * 10;
}
while(i <= Count - pos)
{
temp = temp->prev;
i++;
}
}
cout << pos << " Элемент: ";
cout << *temp->data << endl;
}
template <typename T>
void List<T>::Print()
{
if(Count != 0)
{
Elem<T> * temp = Head;
while(temp != 0)
{
cout << *temp->data<< ' ';
temp = temp->next;
}
}
cout << endl;
}
template <typename T>
void List<T>::DelAll()
{
Elem<T> *elem = Head;
while (elem != NULL) {
Elem<T>* prev = elem;
elem = elem->next;
delete prev->data;
delete prev;
}
TenElems.clear();
Head = Tail = NULL;
}
template <typename T>
void List<T>::Insert()
{
int pos = 0;
cout << "Введите позицию: ";
cin >> pos;
if(pos < 1 || pos > Count + 1)
{
cout << "Неправильная позиция !!!\n";
return;
}
if(pos == Count + 1)
{
T data;
cout << "Введите новые данные: ";
cin >> data;
AddTail(&data);
return;
}
else if(pos == 1)
{
T data;
cout << "Введите новые данные : ";
cin >> data;
AddHead(&data);
return;
}
int i = 1;
Elem<T>* Ins = Head;
int tens = pos / 10;
if (tens > 0) {
Ins = TenElems[tens - 1];
pos -= tens * 10;
}
while(i < pos)
{
Ins = Ins->next;
i++;
}
Elem<T>* PrevIns = Ins->prev;
Elem<T>* temp = new Elem<T>;
cout << "Введите новый номер: ";
temp->data = new T;
cin >> *temp->data;
if(PrevIns != 0 && Count != 1)
PrevIns->next = temp;
temp->next = Ins;
temp->prev = PrevIns;
Ins->prev = temp;
Count++;
if (Count % 10 == 0)
TenElems.push_back(Ins);
}
template <typename T>
int List<T>::GetCount()
{
return Count;
}
template <class T>
void List<T>::SaveBin(const char *name) //сохранение в двоичный файл
{
if (Head==NULL)
{
cout<<"\nПустой список\n"; return;
}
ofstream File(name,ios::binary); //создание файла для сохранения
File.write((char *)&Count,sizeof(int)); //запись в файл кол-ва элементов
for(Elem<T> *pt = Head; pt != NULL; pt = pt->next) //запись даты
{
if (pt->data == 0) {
T nul=0;
File.write((char *)&nul, sizeof(T)); //запись нулей
continue;
}
File.write((char*)pt->data, sizeof(T));
}
cout << "Сохранено в файл ''" << name << "''\n\n";
}
template <>
void List<string>::SaveBin(const char *name) {
if (Head==NULL)
{
cout<<"\nПустой список \n";
return;
}
ofstream File(name,ios::binary);
Elem<string> *pt = Head;
File.write((char *)&Count,sizeof(int));
for(pt = Head; pt != NULL; pt = pt->next)
{
if (pt->data == 0) {
int nul=0; File.write((char *)&nul,sizeof(int));
continue;
}
int len = pt->data->length(); File.write((char*)&len, sizeof(int));
File.write(pt->data->c_str(), len); }
cout << "Сохраненов в файл ''" << name << "''\n\n";
}
template <class T>
void List<T>::LoadBin(const char *name) //Загрзка из двоичного файла
{
ifstream File(name, ios::binary); //открытие файла для загрузки
if (!File) {
cout<<"Не может быть открыта"; return;
} if (Count != 0)
DelAll(); //очистить список
int n;
Elem<T> *pt = new Elem<T>;
Elem<T> *firstpt = pt; //запомнить первый элемент
File.read((char *)&Count, sizeof(int)); //загрузка кол-ва элементов
for (int n = Count ; n > 0; n--) //цикл по всем элементам
{
T tmp;
pt->next=NULL;
File.read((char*)&tmp, sizeof(T));
if (tmp == 0) pt->data = NULL; //если встретили 0 - записать NULL-указатель
else
pt->data = new T(tmp); //иначе записать дату в список
if (n != 1) //проверка, чтобы не создавать последний пустой
{
Elem<T> *temppt = new Elem<T>;
pt->next = temppt;
pt->next->prev = pt;
pt = temppt;
}
}
Head = firstpt; //возврат первого
Tail = pt;
RecomputeTens();
cout << "Загрузить из файла ''" << name << "''\n\n";
}
template <>
void List<string>::LoadBin(const char *name) //Загрузка из двоичного файла
{
ifstream File(name,ios::binary);
if (!File)
{ cout<<"Не может быть открыта ";
return;
}
DelAll();
Elem<string> *pt = new Elem<string>;
Elem<string> *firstpt = pt;
File.read((char *)&Count, sizeof(int));
for (int n = Count; n > 0; n--)
{
int len;
pt->next=NULL;
File.read((char *)&len, sizeof(int)); //загрузка длины строки
if (len == 0)
{
pt->data=NULL;
continue;
}
else
{
char *tmp = new char[len+1]; //выделение памяти под строку
tmp[len] = 0; //ограничитель
File.read(tmp, len); //считывание строки
pt->data = new string(tmp); //копия в динамическую память
}
if (n != 1)
{
Elem<string> *temppt=new Elem<string>;
pt->next=temppt;
pt->next->prev=pt;
pt=temppt;
}
}
Head = firstpt;
Tail = pt;
cout << "Загрузить из файла ''" << name << "''\n\n";
}
1
Документ
Категория
Рефераты
Просмотров
10
Размер файла
261 Кб
Теги
записка
1/--страниц
Пожаловаться на содержимое документа