Министерство образования и науки РФ

Новосибирский государственный технический университет


Кафедра ВТ

Курсовая работа

По дисциплине: «Программирование. Раздел 2 – Объектно-ориентированное программирование на С++»

Шаблон иерархической структуры данных в памяти

Факультет: АВТ

Группа: АМ-610

Студент:

Преподаватель:

Вариант: 6

Новосибирск, 2007


Техническое задание.

Для заданной двухуровневой структуры данных, содержащей указатели на объекты (или сами объекты) - параметры шаблона, разработать полный набор операций (добавление, включение и извлечение по логическому номеру, сортировка, включение с сохранением порядка, загрузка и сохранение объектов в бинарном файле, балансировка – выравнивание размерностей структур данных нижнего уровня). Предполагается, что операции сравнения хранимых объектов переопределены стандартным образом (в виде операций <,> и т. д.).

Проверить шаблон на простых типах и сложных типах. В качестве сложного типа можно использовать объекты - строки. Программа должна реализовывать указанные выше действия. Протестировать шаблон. Программа тестирования должна содержать меню, обеспечивающее выбор операций.

Шаблон структуры данных – двусвязный список (нециклический), каждый элемент списка содержит указатель на объект. Для ускорения процедуры обхода структуры данные имеется динамический массив указателей на каждый 10-ый элемент списка (0,10,20 и т. д.).

2.  Назначение и область применения программного продукта.

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

НЕ нашли? Не то? Что вы ищете?

3.  Теоретический материал.

Наследование - это процесс, посредством которого один объект может приобретать свойства другого. Точнее, объект может наследовать основные свойства другого объекта и добавлять к ним черты, характерные только для него. Наследование является важным, поскольку оно позволяет поддерживать концепцию иерархии классов (hierarchical classification). Применение иерархии классов делает управляемыми большие потоки информации.

Виртуальные функции. Виртуальные функции преодолевают сложности решения с помощью полей типа, позволяя программисту описывать в базовом классе функции, которые можно переопределять в любом производном классе. Компилятор и загрузчик обеспечивают правильное соответствие между объектами и применяемыми к ним функциями.

Шаблоны. В языке C++ возможно и параметрическое программирование (программирование с использованием родовых компонентов). Родовые (параметризованные) компоненты обладают свойством адаптивности к конкретной ситуации, в которой такой компонент используется, что позволяет разрабатывать достаточно универсальные и в то же время высокоэффективные компоненты программ (в частности, объекты).

Параметрическое программирование в языке C++ реализовано с помощью шаблонов (template). В C++ определено два вида шаблонов: шаблоны-классы и шаблоны-функции.

Шаблоны-классы могут использоваться многими способами, но наиболее очевидным является их использование в качестве адаптивных объектов памяти. Шаблоны-функции могут использоваться для определения параметризованных алгоритмов. Основное отличие шаблона-функции от шаблона-класса в том, что не нужно сообщать компилятору, к каким типам параметров применяется функция, он сам может определить это по типам ее формальных параметров.

Шаблоны, которые называют иногда родовыми или параметризованными типами, позволяют создавать (конструировать) семейства родственных функций и классов.

Цель введения шаблонов функций - автоматизация создания функций, которые могут обрабатывать разнотипные данные. В отличие от механизма перегрузки, когда для каждого набора формальных параметров определяется своя функция, шаблон семейства функций определяется один раз, но это определение параметризуется. Параметризовать в шаблоне функций можно тип возвращаемого функцией значения и типы любых параметров, количество и порядок размещения которых должны быть фиксированы. Для параметризации используется список параметров шаблона.

Можно считать, что параметры шаблона являются его формальными параметрами, а типы тех параметров, которые используются в конкретных обращениях к функции, служат фактическими параметрами шаблона. Именно по ним выполняется параметрическая настройка и с учетом этих типов генерируется конкретный текст определения функции. Однако, говоря о шаблоне семейства функций, обычно употребляют термин «список параметров шаблона», не добавляя определения «формальных».

Перечислим основные свойства параметров шаблона:

1.  Имена параметров шаблона должны быть уникальными во всем определении шаблона.

2.  Список параметров шаблона функции не может быть пустым, так как при этом теряется возможность параметризации и шаблон функций становится обычным определением конкретной функции.

3.  В списке параметров шаблона функций может быть несколько параметров. Каждый из них должен начинаться со служебного слова class.

Шаблон семейства классов определяет способ построения отдельных классов подобно тому, как класс определяет правила построения и формат отдельных объектов. В определении класса, входящего в шаблон, особую роль играет имя класса. Оно является не именем отдельного класса, а параметризованным именем семейства классов. Как и для шаблонов функций, определение шаблона класса может быть только глобальным.

Обработка исключительных ситуаций: обработка ошибок в стандартном С. Еще в стандартном Си (ANSI C) имелись средства обнаружения и перехвата различных ошибок, возникающих в процессе выполнения программы, а также других исключительных ситуаций, не приводящих к завершению программы, но не позволяющих ей функционировать должным образом. К таким ситуациям относятся выходы значений переменных из допустимых диапазонов, ошибки в математических операциях и функциях, невозможность выделения требуемого объема динамической памяти. Ошибки, возникшие в процессе выполнения программы, связаны с неверной логикой ее функционирования и не могут быть выявлены на этапах компиляции и линковки, а их возникновение приводит к прекращению работы программы без указания конкретного места возникновения ошибки.

В языке Си++ практически любое состояние, достигнутое в процессе выполнения программы, можно заранее определить как особую ситуацию (исключение) и предусмотреть действия, которые нужно выполнить при ее возникновении.

Для реализации механизма обработки исключений в язык Си++ введены следующие три ключевых (служебных) слова: try (контролировать), catch (ловить), throw (генерировать, порождать, бросать, посылать, формировать).

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

try {операторы}

Среди операторов, заключенных в фигурные скобки могут быть: описания, определения, обычные операторы языка Си++ и специальные операторы генерации (порождения, формирования) исключений:

throw выражение_генерации_исключения;

Когда выполняется такой оператор, то с помощью выражения, использованного после служебного слова throw, формируется специальный объект, называемый исключением. Исключение создается как статический объект, тип которого определяется типом значения выражения_генерации_исключения. После формирования исключения исполняемый оператор throw автоматически передает управление (и само исключение как объект) непосредственно за пределы контролируемого блока. В этом месте (за закрывающейся фигурной скобкой) обязательно находятся один или несколько обработчиков исключений, каждый из которых идентифицируется служебным словом catch и имеет в общем случае следующий формат:

catch (тип_исключения имя) { операторы }

Об операторах в фигурных скобках говорят как о блоке обработчика исключений. Обработчик исключений (процедура обработки исключений) внешне и по смыслу похож на определение функции с одним параметром, не возвращающей никакого значения. Когда обработчиков несколько, они должны отличаться друг от друга типами исключений. Все это очень похоже на перегрузку функций, когда несколько одноименных функций отличаются спецификациями параметров. Так как исключение передается как объект определенного типа, то именно этот тип позволяет выбрать из нескольких обработчиков соответствующий посланному исключению.

Механизм обработки исключений является весьма общим средством управления программой. Он может использоваться не только при обработке аварийных ситуаций, но и любых других состояний в программе, которые почему-либо выделил программист. Для этого достаточно, чтобы та часть программы, где планируется возникновение исключений, была оформлена в виде контролируемого блока, в котором выполнялись бы операторы генерации исключений при обнаружении заранее запланированных ситуаций.

Переопределение операций: язык C++ не обеспечивает средств для ввода/вывода. Ему это и не нужно; такие средства легко и элегантно можно создать с помощью самого языка. Описанная здесь стандартная библиотека потокового ввода/вывода обеспечивает гибкий и эффективный с гарантией типа метод обработки символьного ввода целых чисел, чисел с плавающей точкой и символьных строк, а также простую модель ее расширения для обработки типов, определяемых пользователем.

Разработка и реализация стандартных средств ввода/вывода для языка программирования зарекомендовала себя как заведомо трудная работа. Традиционно средства ввода/вывода разрабатывались исключительно для небольшого числа встроенных типов данных. Однако в C++ программах обычно используется много типов, определенных пользователем, и нужно обрабатывать ввод и вывод также и значений этих типов. Очевидно, средство ввода/вывода должно быть простым, удобным, надежным в употреблении, эффективным и гибким, и ко всему прочему полным. Ничье решение еще не смогло угодить всем, поэтому у пользователя должна быть возможность задавать альтернативные средства ввода/вывода и расширять стандартные средства ввода/вывода применительно к требованиям приложения.

C++ разработан так, чтобы у пользователя была возможность определять новые типы столь же эффективные и удобные, сколь и встроенные типы. Поэтому обоснованным является требование того, что средства ввода/вывода для C++ должны обеспечиваться в C++ с применением только тех средств, которые доступны каждому программисту. Описываемые здесь средства ввода/вывода представляют собой попытку ответить на этот вызов.

Средства ввода/вывода связаны исключительно с обработкой преобразования типизированных объектов в последовательности символов и обратно. Есть и другие схемы ввода/вывода, но эта является основополагающей в системе UNIX, и большая часть видов бинарного ввода/вывода обрабатывается через рассмотрение символа просто как набор бит, при этом его общепринятая связь с алфавитом игнорируется. Тогда для программиста ключевая проблема заключается в задании соответствия между типизированным объектом и принципиально нетипизированной строкой.

Обработка и встроенных и определенных пользователем типов однородным образом и с гарантией типа достигается с помощью одного перегруженного имени функции для набора функций вывода.

4.  Структурное описание разработки.

Реализация списка осуществлена при помощи шаблонного класса ListBase, от которого наследуются класс List для работы с простыми типами данных и класс List<date>, специализированный для работы со сложным типом данных date (класс дата-время), и класса Elem. Класс Elem является элементом списка. Он содержит указатель на элементы типа T, указатели на следующий элемент списка Elem *next и на предыдущий Elem *prev (список двусвязный, нециклический).

Класс ListBase содержит указатели на первый и последний элементы списка (Elem *first; Elem *last;), а так же динамический массив указателей на каждый 10-й элемент списка Elem **pp (для ускорения обхода структуры). Отметим, что указатели на 10-ые элементы структуры предполагают объемную структуру данных; т. к. в учебных целях мы используем структуры гораздо более меньших размеров, то целесообразнее сделать шаг меньше. С этой целью по умолчанию указан шаг 2 (#define STEP 2), который можно изменить на 10, либо на какое-либо другое значение.

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

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


Описание программы.

В начале своей работы, программа предлагает пользователю выбрать простой тип данных (int) либо сложный (date).

Далее на экран выводится меню управления, которое позволяет получить доступ к следующим операциям:

Рассмотрим каждую операцию отдельно:

1. Добавление элемента:

Вставка элемента в конец структуры данных.

2. Включение по логическому номеру:

Вставка элемента по логическому номеру: просматривается массив указателей на каждый 10-й элемент, вычисляется элемент этого массива, с которого целесообразно начать просмотр списка, далее находится место вставки и элемент вставляется

3. Включение с сохранением порядка:

Вставка элемента в конец структуры данных и сортировка.

4. Получение по логическому номеру:

Просматривается массив указателей на каждый 10-й элемент, вычисляется элемент этого массива, с которого целесообразно начать просмотр списка, далее находится нужный элемент (с нужным логическим номером) и возвращается.

5. Вывод на экран:

Вывод списка на экран с использованием итератора

6. Сортировка:

Сортировка выбором с использованием итератора.

Сохранение в файл:

Запись содержимого списка в бинарный файл.

Чтение из файла:

Чтение значений из бинарного файла и занесение их в список.

Формат файла: кол-во элементов списка, далее следуют сами данные элементов

6.  Текст программы с комментариями

//=============date. h============

#pragma once

#include <time. h>

#include <iostream> // Подключение необходимых библиотек

#include "Exception. h"

#define MON 0

#define MDAY 1

#define HOUR 2

#define MIN 3

#define SEC 4

#define YEAR 5

class date // Класс дата

{

protected:

int tmpYear;

public:

struct tm *stime; // Используется структура tm

date(); // Конструкторы

date(int null);

date(int mon, int mday, int hour, int min, int sec, int year);

date(tm* st);

date(const date &dt); // Конструктор копирования

~date(); // Деструктор

date & operator =(const date &dt); // Переопределение операций

date & operator =(const tm *st);

operator tm*();

virtual operator char*();

int & operator [](int n);

void updateYear(); // Методы для работы с классом

static int maxDayInMon(int mon, int year);

void setDate(int mon, int mday, int hour, int min, int sec, int year);

void setDate(const tm *st);

tm* getDate();

int getField(int n);

void incrField(int n);

void decrField(int n);

void changeField(int n, int val);

void printDate(ostream *os=&cout);

int operator > (date &d);

friend istream & operator >> (istream &is, date &d);

};

//=============Exceptions. h============

#pragma once

#define CHECK_BOUND(val, low, high) if ((val<low) || (val>high)) throw new BoundException();

#define CHECK_ENTRY if (cin. fail())\

{\

cin. clear();\

char c;\

cin >> c;\

cout << "Invalid Entry" <<endl;\

continue;\

}

#include <iostream>

using namespace std;

class Exception

{

public:

virtual void PrintError()=0;

Exception(){}

~Exception(){}

};

class BoundException: public Exception

{

public:

BoundException(){}

void PrintError()

{

cout << "ERROR: BoundException thrown, (n<0) || (n>=count)" << endl;

}

};

class ArgException: public Exception

{

public:

ArgException(){}

void PrintError()

{

cout << "ERROR: ArgException thrown, n doesn't match the number of the field" << endl;

}

};

class MemException: public Exception

{

char errorBuf[1024];

public:

MemException(char *str)

{

strcpy(errorBuf, str);

}

void PrintError()

{

cout<<"ERROR: MemException thrown, details: "<<errorBuf<<endl;

}

};

class FileException: public Exception

{

char errorBuf[1024];

public:

FileException(char *str)

{

strcpy(errorBuf, str);

}

void PrintError()

{

cout<<"ERROR: FileException thrown, cannot open file: "<<errorBuf<<endl;

}

};

class StackException: public Exception

{

public:

void PrintError()

{

cout<<"ERROR: StackException thrown, stack is empty." << endl;

}

};

//=============list. h============

#pragma once

#include <stdio. h>

#include <stdlib. h>

#include <string. h>

#include "date. h"

#define ARRAY_SZ 10

#define STEP 2

template <class T> class ListBase;

template <class T> class List;

template <> class List<date>;

template <class T>

class Elem //класс элемент списка

{

Elem <T> *next;

Elem <T> *prev;

T* data;

public:

Elem(T* ptr);

~Elem();

friend class ListBase <T>;

friend class ListBase <T>::Iterator;

friend class List<date>;

friend class List<T>;

};

template <class T> //класс список

class ListBase

{

protected:

Elem <T> *first;

Elem <T> *last;

Elem <T> **pp; //указатель на массив указателей на каждый 10-й элемент списка

int ArraySz;

int ArrayInd;

void AddToPtrArray(Elem <T> *ptr); //добавление в массив pp

void InsertToPtrArray(Elem <T> *ptr, int ind);

public:

class Iterator

{

Elem<T> *cur;

Elem<T> *first;

int m_End;

public:

Iterator(ListBase <T> *ptr):first(ptr->first)

{

begin();

}

void begin()

{

cur=first;

m_End=cur==NULL;

}

int end(){return m_End;}

T& operator ++ ()

{

if (m_End)

throw "Blocked";

T& val=*(cur->data);

cur=cur->next;

if (!cur) m_End=1;

return val;

}

T& operator *()

{

if (m_End)

throw "Blocked";

return *(cur->data);

}

};

T* GetDataByIndex(int index); //извлечение данных по логическому номеру

void InsertDataByIndex(T* data, int index); //вставка в список по логическому номеру

void InsertDataByOrder(T* data); //вставка в список c сохранением порядка

void AddDataToStructure(T* data); //добавление в конец списка

void Sort(); //сортировка

int SaveBin(char *fn); //сохранение структуры данных в файл

int GetCount();

ListBase(T* _first);

ListBase(char *fn); //конструктор загрузки данных из файла

~ListBase();

ListBase(){}

};

//шаблон для простых типов-----

template <class T>

class List: public ListBase<T>

{

public:

List(char *fn):ListBase(fn) {}

List(T *_first):ListBase(_first){}

};

//специализированный шаблон для типа date--

template<>

class List<date>: public ListBase<date>

{

public:

date GetDataByIndex(int index) //извлечение по логическому номеру

{

int i=0;

Elem<date> *p;

Elem<date> *fst;

if (index/STEP > 0)

{

i=(index/STEP)*STEP;

fst=pp[index/STEP];

}

else

fst=first;

for (p=fst;p!=NULL && i!=index;i++,p=p->next);

return *(p->data);

}

List(char *fn)

{

ArraySz=ARRAY_SZ;

ArrayInd=0;

pp=new Elem<date>*[ArraySz];

for (int i=0;i<ArraySz;i++)

pp[i]=NULL;

first=last=NULL;

FILE *f=fopen(fn,"r");

if (f==NULL)

throw "ListBase(): Cannot open file";

int cnt;

fread(&cnt, sizeof(int),1,f);

date *ptr;

for (int i=0;i<cnt;i++)

{

ptr=new date();

fread(ptr->stime, sizeof(tm),1,f);

AddDataToStructure(ptr);

}

}

List(date *_first):ListBase(_first){}

int SaveBin (char *fn) //сохранение списка в файл

{

FILE *f=fopen(fn,"w");

if (f==NULL)

return -1;

Elem<date> *p;

int cnt=GetCount();

fwrite(&cnt, sizeof(int),1,f);

for (p=first;p!=NULL;p=p->next)

fwrite(p->data->stime, sizeof(tm),1,f);

fclose(f);

return 0;

}

};

//-

template <class T> Elem<T>::Elem(T *ptr) //конструктор класса Elem

{

data=ptr;

}

template <class T> Elem<T>::~Elem() //деструктор класса Elem

{

delete data;

}

template <class T> ListBase<T>::ListBase(T *_first) //конструктор класса ListBase (добавляет первый элемент в список)

{

ArraySz=ARRAY_SZ;

ArrayInd=0;

pp=new Elem<T>*[ArraySz];

for (int i=0;i<ArraySz;i++)

pp[i]=NULL;

first=last=NULL;

AddDataToStructure(_first);

}

template <class T> T* ListBase<T>::GetDataByIndex(int index) //извлечение по логическому номеру

{

int i=0;

Elem<T> *p;

Elem<T> *fst;

if (index/STEP > 0)

{

i=(index/STEP)*STEP;

fst=pp[index/STEP];

}

else

fst=first;

for (p=fst;p!=NULL && i!=index;i++,p=p->next);

return p->data;

}

template <class T> ListBase<T>::ListBase(char *fn) //конструктор класса ListBase (читает данные списка из файла)

{

ArraySz=ARRAY_SZ;

ArrayInd=0;

pp=new Elem<T>*[ArraySz];

for (int i=0;i<ArraySz;i++)

pp[i]=NULL;

first=last=NULL;

FILE *f=fopen(fn,"r");

if (f==NULL)

throw "ListBase(): Cannot open file";

int cnt;

fread(&cnt, sizeof(int),1,f);

T *ptr;

for (int i=0;i<cnt;i++)

{

ptr=new T();

fread(ptr, sizeof(T),1,f);

AddDataToStructure(ptr);

}

}

template <class T> ListBase<T>::~ListBase() //деструктор

{

Elem <T> *p;

for (p=last;p!=NULL;)

{

p=p->prev;

if (p) delete p->next;

}

delete first;

}

template <class T> void ListBase<T>::AddDataToStructure(T* data) //добавление элемента в список

{

if (first==NULL)

{

last=first=new Elem <T>(data);

AddToPtrArray(last);

last->next=last->prev=NULL;

}

else

{

int cnt=GetCount();

last->next=new Elem <T>(data);

last->next->prev=last;

last->next->next=NULL;

last=last->next;

if (cnt % STEP==0)

AddToPtrArray(last);

}

}

template <class T> void ListBase<T>::InsertDataByIndex(T* data, int index) //вставка по логическому номеру

{

int i=0;

Elem<T> *p;

Elem<T> *fst;

if (index/STEP>0)

{

i=(index/STEP)*STEP;

fst=pp[index/STEP];

}

else

fst=first;

for (p=fst;p!=NULL && i!=index;i++,p=p->next);

if (p==NULL)

AddDataToStructure(data);

else

{

Elem <T> *ptr=new Elem<T>(data);

ptr->prev=p->prev;

if (p->prev)

p->prev->next=ptr;

else

first=ptr;

ptr->next=p;

p->prev=ptr;

if (index % STEP==0)

InsertToPtrArray(ptr,(index)/STEP);

}

}

template <class T> void ListBase<T>::InsertDataByOrder(T* data) //вставка с сохранением порядка

{

AddDataToStructure(data);

Sort();

}

template <class T> void ListBase<T>::Sort() //сортировка списка

{

T tmp;

ListBase<T>::Iterator it1(this);

ListBase<T>::Iterator it2(this);

for (it1.begin();!it1.end();it1++)

for (it2.begin();!it2.end();it2++)

{

if (*it2>*it1)

{

tmp=*it1;

*it1=*it2;

*it2=tmp;

}

}

}

template <class T> int ListBase<T>::GetCount() //возвращает количество элементов списка

{

Elem <T> *p;

int i;

for (i=0,p=first;p!=NULL;p=p->next, i++);

return i;

}

template <class T> int ListBase<T>::SaveBin (char *fn) //сохранение списка в файл

{

FILE *f=fopen(fn,"w");

if (f==NULL)

return -1;

Elem<T> *p;

int cnt=GetCount();

fwrite(&cnt, sizeof(int),1,f);

for (p=first;p!=NULL;p=p->next)

fwrite(p->data, sizeof(T),1,f);

fclose(f);

return 0;

}

template <class T> void ListBase<T>::AddToPtrArray(Elem <T> *ptr) //добавление в массив pp

{

if (ArrayInd+1==ArraySz)

{

pp=(Elem <T>**)realloc(pp, sizeof(Elem<T>*)*ArraySz*2);

ArraySz*=2;

}

pp[ArrayInd++]=ptr;

}

template <class T> void ListBase<T>::InsertToPtrArray(Elem <T> *ptr, int ind) //вставка в массив pp по логическому номеру

{

int i, j;

if (ArrayInd+1==ArraySz)

{

pp=(Elem <T>**)realloc(pp, sizeof(Elem<T>*)*ArraySz*2);

ArraySz*=2;

}

Elem <T> *p;

pp[ind]=ptr;

for (i=ind, j=ind*STEP, p=pp[ind];p!=NULL;p=p->next, j++)

if (j % STEP==0)

pp[i++]=p;

}

//=============date. cpp============

#include <iostream>

#include <stdlib. h>

#include <time. h>

#include "date. h"

#include <windows. h> // Подключение необходимых библиотек

#include <fstream>

using namespace std;

date::date() // Конструктор без параметров

{ // устанавливает системное время

time_t systime;

time(&systime);

stime = new tm;

localtime_s(stime,&systime);

}

date::date(int null) // Конструктор с параметром

{ // устанавливает все поля на начальные значения (Янв 1 03:00:00 1900 год)

time_t temp;

temp=0;

stime=new tm;

localtime_s(stime,&temp);

}

date::date(int mon, int mday, int hour, int min, int sec, int year) // Конструктор с параметрами

{ // установливает все поля в соответствии со значениями входящих параметров

stime = new tm;

stime->tm_mon=mon;

stime->tm_mday=mday;

stime->tm_hour=hour;

stime->tm_min=min;

stime->tm_sec=sec;

stime->tm_year=year-1900; // Поправка года

}

date::date(tm* st) // Конструктор с параметром

{ // устанавливает все поля в соответствии с полями структуры st

stime = new tm;

stime->tm_mon=st->tm_mon;

stime->tm_mday=st->tm_mday;

stime->tm_hour=st->tm_hour;

stime->tm_min=st->tm_min;

stime->tm_sec=st->tm_sec;

stime->tm_year=st->tm_year;

}

date::date(const date &dt) // Конструктор копирования

{ // вызывается при копировании объекта date

stime = new tm;

setDate(dt. stime);

}

date::~date() // Деструктор

{

if (stime!=NULL)

delete stime;

}

date & date::operator =(const date &dt) // Операция присваивания объекта типа date

{

if (this==&dt)

return *this;

setDate(dt. stime);

return *this;

}

date & date::operator =(const tm *st) // Операция присваивания указателя на tm

{

if (!memcmp(&stime,&st, sizeof(tm)))

return *this;

setDate(st);

return *this;

}

date::operator tm*() // Приведение к типу tm*

{

return stime;

}

date::operator char*() // Приведение к типу char*

{

char *buf;

buf=new char[32];

time_t temp;

temp=mktime(stime);

errno_t errNum;

errNum = ctime_s(buf,32,&temp);

return buf;

}

int & date::operator [](int n) // Операция индексирования

{

if (n==MON)

return stime->tm_mon;

if (n==MDAY)

return stime->tm_mday;

if (n==HOUR)

return stime->tm_hour;

if (n==MIN)

return stime->tm_min;

if (n==SEC)

return stime->tm_sec;

if (n==YEAR)

{

tmpYear=stime->tm_year+1900;

return tmpYear;

}

throw new ArgException();

}

void date::updateYear()

{

stime->tm_year=tmpYear-1900;

}

tm* date::getDate() // Функция получения даты

{

return stime; // Возвращает указатель на структуру tm

}

int date::getField(int n) // Функция получения значения поля

{

if (n==MON)

return stime->tm_mon;

if (n==MDAY)

return stime->tm_mday;

if (n==HOUR)

return stime->tm_hour;

if (n==MIN)

return stime->tm_min;

if (n==SEC)

return stime->tm_sec;

if (n==YEAR)

return stime->tm_year+1900;

throw new ArgException();

}

void date::setDate(int mon, int mday, int hour, int min, int sec, int year)

{ // Функция установки всех полей в соответствии с заданными значениями

CHECK_BOUND(mon,0,11)

CHECK_BOUND(year,1970,3000)

CHECK_BOUND(mday,1,maxDayInMon(mon, year))

CHECK_BOUND(hour,0,23)

CHECK_BOUND(min,0,59)

CHECK_BOUND(sec,0,59)

stime->tm_mon=mon;

stime->tm_mday=mday;

stime->tm_hour=hour;

stime->tm_min=min;

stime->tm_sec=sec;

stime->tm_year=year-1900; // Поправка года

}

void date::setDate(const tm* st)

{ // Функция установки всех полей в соответствии с полями st

memcpy(stime, st, sizeof(tm));

}

int date::maxDayInMon(int mon, int year) // Функция получения количества дней в месяце

{

int monArray[13]={31,28,31,30,31,30,31,31,30,31,30,31,29};

bool leapCheck=0;

if ((year%400==0) || (year%4==0) && (year%100!=0)) // Проверка на високосный год

leapCheck=1;

if ( (mon==1) && leapCheck ) // Февраль високосного года

mon=12;

return monArray[mon]; // Возвращает максимальное количество дней в текущем месяце

}

void date::changeField(int n, int val) // Функция изменения поля на заданное значение

{

if (n==MON)

{

CHECK_BOUND(val,0,11);

stime->tm_mon=val;

}

if (n==YEAR)

{

CHECK_BOUND(val,1970,3000);

stime->tm_year=val-1900; // Поправка года

}

if (n==MDAY)

{

CHECK_BOUND(val,1,maxDayInMon(0,0));

stime->tm_mday=val;

}

if (n==HOUR)

{

CHECK_BOUND(val,0,24);

stime->tm_hour=val;

}

if (n==MIN)

{

CHECK_BOUND(val,0,59);

stime->tm_min=val;

}

if (n==SEC)

{

stime->tm_sec=val;

}

throw new ArgException();

}

void date::incrField(int n) // Рекурсивная функция инкремента одного из полей даты

{

time_t temp;

temp=mktime(stime);

if (n==SEC) // Для поля секунд

temp=temp+1;

else

if (n==MIN) // Для поля минут

temp=temp+60;

else

if (n==HOUR) // Для поля часов

temp=temp+3600;

else

if (n==MDAY) // Для поля дней месяца

temp=temp+3600*24;

else

if (n==MON) // Для поля месяцев

temp=temp+3600*24*30;

else

if (n==YEAR) // Для поля лет

temp=temp+3600*24*30*12;

else

throw new ArgException();

if (temp<=3600*24*30*12*3000)

{

localtime_s(stime,&temp);

}

}

void date::decrField(int n) // Рекурсивная функция декремента одного из полей даты

{

time_t temp;

temp=mktime(stime);

if (n==SEC) // Для поля секунд

temp=temp-1;

else

if (n==MIN) // Для поля минут

temp=temp-60;

else

if (n==HOUR) // Для поля часов

temp=temp-3600;

else

if (n==MDAY) // Для поля дней месяца

temp=temp-3600*24;

else

if (n==MON) // Для поля месяцев

temp=temp-3600*24*30;

else

if (n==YEAR) // Для поля лет

temp=temp-3600*24*30*12;

else

throw new ArgException();

if (temp>=0)

{

localtime_s(stime,&temp);

}

}

void date::printDate(ostream *os) // Вывод даты и времени на экран в формате Month dd hh:mm:ss year

{

(*os) <<*this<<endl;

}

int date::operator > (date &d)

{

if (stime->tm_year == d. stime->tm_year)

{

if (stime->tm_mon == d. stime->tm_mon)

{

if ( stime->tm_mday == d. stime->tm_mday)

{

if (stime->tm_hour == stime->tm_hour)

{

if (stime->tm_min == stime->tm_min)

{

return stime->tm_sec > stime->tm_sec;

}

else

return stime->tm_min > stime->tm_min;

}

else

return stime->tm_hour > stime->tm_hour;

}

else

return stime->tm_mday > d. stime->tm_mday;

}

else

return stime->tm_mon >d. stime->tm_mon;

}

else

return stime->tm_year >d. stime->tm_year;

}

//=============Main. cpp============

#include "list. h"

#include <iostream>

#include <conio. h>

using namespace std;

template <class T> //функция вывода

void Print(List <T> *ph)

{

cout << "List elements: " <<endl;

List<T>::Iterator it(ph);

int i;

for (i=0,it. begin();!it. end();it++,i++)

cout<<i<<"-th: "<<*it<<endl;

}

date* EnterDate()

{

tm t;

while (1)

{

cout << "date: Enter date value: "<<endl;

cout <<endl<<"mon, mday, hour, min, sec, year:"<<endl;

cin>>t. tm_mon>>t. tm_mday>>t. tm_hour>>t. tm_min>>t. tm_sec>>t. tm_year;

try

{

CHECK_BOUND(t. tm_mon,0,11)

CHECK_BOUND(t. tm_year,1970,3000)

CHECK_BOUND(t. tm_mday,1,date::maxDayInMon(t. tm_mon, t.tm_year))

CHECK_BOUND(t. tm_hour,0,23)

CHECK_BOUND(t. tm_min,0,59)

CHECK_BOUND(t. tm_sec,0,59)

break;

}

catch (BoundException *e)

{

e->PrintError();

delete e;

}

}

t. tm_year-=1900;

date *tmp2=new date(&t);

return tmp2;

}

void main()

{

List <int> *ph1=NULL;

List <date> *ph2=NULL;

cout<<"Choose: 0 - int, 1 - date "; //выбор типа, на котором тестируется шаблон

int t;

t=getch()-'0';

int k, m;

int *tmp1;

date *tmp2;

char str[256];

while(1)

{

cout <<endl<<"MENU:" <<endl

<<"1 - Add to list" <<endl

<<"2 - Insert by logical number"<<endl

<<"3 - Insert by order" <<endl

<<"4 - Get by logical number"<<endl

<<"5 - Print"<<endl

<<"6 - Sort"<<endl

<<"7 - Save to binary file"<<endl

<<"8 - Load from binary file"<<endl

<<"Other - exit"<<endl;

m=getch()-'0';

if (ph1==NULL && ph2==NULL && m!=8 && m!=1 && m!=0)

{

cout<<"List is empty"<<endl;

continue;

}

if ((ph1!=NULL || ph2!=NULL) && m==8)

{

cout<<"You already have list, restart program to initialize list with file"<<endl;

continue;

}

switch(m)

{

case 1: //добавление в конец

{

if (!t)

{

tmp1=new int;

cout<<"Enter integer value: "<<endl;

cin>>*tmp1;

if (!ph1)

{

ph1=new List <int>(tmp1);

}

else

ph1->AddDataToStructure(tmp1);

}

else

{

tmp2 = EnterDate();

if (!ph2)

{

ph2=new List <date>(tmp2);

}

else

ph2->AddDataToStructure(tmp2);

}

cout << "\nOK\n";

break;

}

case 2: //вставка по логическому номеру

{

cout<<"Enter logical number"<<endl;

cin>>k;

if (!t)

{

if (k<0 || k>=ph1->GetCount())

{

cout <<"Incorrect index"<<endl;

break;

}

tmp1=new int;

cout<<"Enter integer value:"<<endl;

cin>>*tmp1;

ph1->InsertDataByIndex(tmp1,k);

}

else

{

if (k<0 || k>=ph2->GetCount())

{

cout<<"Incorrect index"<<endl;

break;

}

tmp2 = EnterDate();

ph2->InsertDataByIndex(tmp2,k);

}

cout << "\nOK\n";

break;

}

case 3: //вставка с сохранением порядка

{

if (!t)

{

tmp1=new int;

cout<<"Enter integer value: "<<endl;

cin>>*tmp1;

if (!ph1)

{

ph1=new List <int>(tmp1);

}

else

ph1->InsertDataByOrder(tmp1);

}

else

{

tmp2 = EnterDate();

if (!ph2)

{

ph2=new List <date>(tmp2);

}

else

ph2->InsertDataByOrder(tmp2);

}

cout<<"\nOK\n";

break;

}

case 4: //извлечение по логическому номеру

{

cout<<"Enter logical number"<<endl;

cin>>k;

if (!t)

{

if (k<0 || k>=ph1->GetCount())

{

cout<<"Incorrect index"<<endl;

break;

}

cout<<k<<"-th element: "<<*(ph1->GetDataByIndex(k))<<endl;

}

else

{

if (k<0 || k>=ph2->GetCount())

{

cout<<"Incorrect index"<<endl;

break;

}

cout<<k<<"-th element: "<<(ph2->GetDataByIndex(k))<<endl;

}

cout<<"\nOK\n";

break;

}

case 5: //вывод

{

if (!t)

Print<int>(ph1);

else

Print<date>(ph2);

cout<<"\nOK\n";

break;

}

case 6: //сортировка

{

if (!t)

ph1->Sort();

else

ph2->Sort();

cout<<"\nOK\n";

break;

}

case 7: //сохранение в файл

{

cout<<"Enter file name ";

cin>>str;

if (!t)

{

if (ph1->SaveBin(str)!=-1)

cout<<"OK"<<endl;

}

else

{

if (ph2->SaveBin(str)!=-1)

cout<<"OK"<<endl;

}

break;

}

case 8: //загрузка из файла

{

cout<<"Enter file name ";

cin>>str;

if (!t)

{

try

{

ph1=new List <int> (str);

cout<<"OK"<<endl;

}

catch (char *str)

{

cout<<str<<endl;

delete ph1;

ph1=NULL;

return;

}

}

else

{

try

{

ph2=new List <date> (str);

cout<<"OK"<<endl;

}

catch (char *str)

{

cout<<str<<endl;

delete ph2;

ph2=NULL;

return;

}

}

break;

}

case 0:default:

if (ph1)

delete ph1;

if (ph2)

delete ph2;

return;

}

}

}