Объектная реализация контейнера на основе комбинированной структуры

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

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 17.12.2014
Размер файла 240,9 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Размещено на http://www.allbest.ru/

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

Объектная реализация контейнера на основе комбинированной структуры

Введение

программирование модуль контейнер

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

Исходные данные: Объектная реализация контейнера на основе комбинированной структуры «Динамический упорядоченный список массивов-стеков»

Ожидаемый результат: «Квартирный фонд»

§ информационные объекты: квартиры жилого дома (свойства: Номер Квартиры, Площадь)

§ квартиры объединяются в рамках объекта Дом (свойство: Номер Дома)

§ дома объединяются в рамках объекта-контейнера Управляющая Компания (свойство - Название)

Требования:

1. Полная объектная реализация с определением классов для всех элементов реализуемой структуры: информационные объекты (обязательно!), объекты-элементы списка (динамическая реализация), объекты-списки, объект-контейнер

2. Имена классов, свойств и методов должны носить содержательный смысл и соответствовать информационной задаче

3. Соблюдение принципа инкапсуляции - использование в классах только закрытых свойств и реализация необходимого набора методов доступа

4. Реализация в классах всех необходимых методов: конструкторы, методы доступа к свойствам, методы добавления и удаления на каждом из двух уровней, метод поиска (при необходимости)

5. Возможность сохранения всей структуры во внешнем файле с обратной загрузкой

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

7. Язык и среда разработки - по выбору: Delphi, Java, C++, С#

1. Теоретическое описание используемых структур данных с алгоритмами реализации основных операций

Стек

Стеком назовем последовательность элементов одного и того же типа, к которой можно добавлять и убирать элементы, причем как добавление новых элементов, так и удаление старых производится с одного и того же конца этой последовательности, называемого вершиной стека. Применяются и другие названия стека - магазин, функционирующий по принципу LIFO (Last - In - First - Out - «последним пришел - первым исключается»). Примеры стека: винтовочный патронный магазин, тупиковый железнодорожный разъезд для сортировки вагонов.

При удалении элемента удаляется всегда тот элемент, который был последним добавлен в стек, таким образом, элементы удаляются в порядке, обратном порядку добавления элементов.

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

Основные операции над стеком - включение нового элемента (английское название push - заталкивать) и исключение элемента из стека (англ. pop - выскакивать).

Полезными могут быть также вспомогательные операции:

· определение текущего числа элементов в стеке;

· очистка стека;

· неразрушающее чтение элемента из вершины стека, которое может быть реализовано, как комбинация основных операций:

pop(); push().

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

Для наглядности рассмотрим небольшой пример, демонстрирующий принцип включения элементов в стек и исключения элементов из стека. На рис. 1 изображены состояния стека:

· а) пустого;

· б - г) после последовательного включения в него элементов с именами 'A', 'B', 'C';

· д, е) после последовательного удаления из стека элементов 'C' и 'B';

· ж) после включения в стек элемента 'D'.

Как видно из рис. 1, стек можно представить, например, в виде стопки книг (элементов), лежащей на столе. Присвоим каждой книге свое название, например A, B, C, D. Тогда в момент времени, когда на столе книг нет, про стек аналогично можно сказать, что он пуст, т.е. не содержит ни одного элемента. Если же мы начнем последовательно класть книги одну на другую, то получим стопку книг (допустим, из n книг), или получим стек, в котором содержится n элементов, причем вершиной его будет являться элемент n+1. Удаление элементов из стека осуществляется аналогичным образом, т.е. удаляется последовательно по одному элементу, начиная с вершины, или по одной книге из стопки.

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

При занесении элемента в стек элемент записывается на место, определяемое указателем стека, затем указатель модифицируется таким образом, чтобы он указывал на следующий свободный элемент (если указатель указывает на последний записанный элемент, то сначала модифицируется указатель, а затем производится запись элемента). Модификация указателя состоит в прибавлении к нему или в вычитании из него единицы (помните, что наш стек растет в сторону увеличения адресов).

Операция исключения элемента состоит в модификации указателя стека (в направлении, обратном модификации при включении) и выборке значения, на которое указывает указатель стека. После выборки слот, в котором размещался выбранный элемент, считается свободным.

Операция очистки стека сводится к записи в указатель стека начального значения - адреса начала выделенной области памяти.

Определение размера стека сводится к вычислению разности указателей: указателя стека и адреса начала области.

Связный список

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

Связный список - это набор элементов, причем каждый из них является частью узла, который также содержит ссылку на узел.

Узлы определяются ссылками на узлы, поэтому связные списки иногда называют самоссылочными структурами. Более того, хотя узел обычно ссылается на другой узел, возможна ссылка на самого себя, поэтому связные списки могут представлять собой циклические структуры.

Обычно под связным списком подразумевается реализация последовательного расположения набора элементов. Начиная с некоторого узла, мы считаем его первым элементом последовательности. Затем прослеживается его ссылка на другой узел, который дает нам второй элемент последовательности и т.д. Поскольку список может быть циклическим, последовательность иногда представляется бесконечной. Чаще всего приходится иметь дело со списками, соответствующими простому последовательному расположению элементов, принимая одно из следующих соглашений для ссылки последнего узла:

- Это пустая (null) ссылка, не указывающая на какой-либо узел.

- Ссылка указывает на фиктивный узел (dummy node), который не содержит элементов.

- Ссылка указывает на первый узел, что делает список циклическим.

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

Список, отражающий отношения соседства между элементами, называется линейным. Если ограничения на длину списка не допускаются, то список представляется в памяти в виде связной структуры. Линейные связные списки являются простейшими динамическими структурами данных.

Линейные списки

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

Пусть тип NodeDesc (desc от descriptor) определены, как показано ниже. Каждая переменная типа NodeDesc содержит три компоненты, а именно идентифицирующий ключ key, указатель на следующий элемент next и, возможно, другую информацию. Для дальнейшего нам понадобятся только key и next.

struct NodeDesc {

int Info;

int key;

NodeDesc * next;

};

NodeDesc * p;

NodeDesc * q;

p, q - указательные переменные

На рис. 1 показан список узлов, причём указатель на первый элемент хранится в переменной р. Вероятно, простейшая операция со списком, показанным на рисунке - это вставка элемента в голову списка. Сначала размещается элемент типа NodeDesc, при этом ссылка (указатель) на него записывается во вспомогательную переменную, скажем q. Затем простые присваивания указателей завершают операцию. Отметим, что порядок этих трех операторов менять нельзя.

q=new NodeDesc;

qnext = р; р = q;

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

р = null; (*начинаем с пустого списка*)

while (n > 0)

{

q=new NodeDesc;

qnext = р; р = q;

qkey = n;

n -;

}

Это простейший способ создания списка. Однако здесь получается, что элементы стоят в обратном порядке по сравнению с порядком их добавления в список. В некоторых задачах это нежелательно, и поэтому новые элементы должны присоединяться в конце, а не в начале списка. Хотя конец списка легко найти простым просмотром, такой наивный подход приводит к вычислительным затратам, которых можно избежать, используя второй указатель, скажем q, который всегда указывает на последний элемент.

Среди элементарных операций со списками-вставка и удаление элементов (частичное изменение списка), а также, разумеется, проход по списку. Мы сначала рассмотрим вставку (insertion) в список.

Предположим, что элемент, на который ссылается указатель q, нужно вставить в список после элемента, на который ссылается указатель р (рис. 2).

qnext = pnext; pnext = q;

Если нужна вставка перед указанным элементом pp, а не после него, то, казалось бы, возникает затруднение, так как в однонаправленной цепочке ссылок никакого пути от элемента к его предшественникам. Однако здесь может выручить простой прием.

Необходимо вставить новую компоненту после pp, а потом произвести обмен значениями между новым элементом и pp.

q=new NodeDesc;

qq=pp;

pkey=k;

pnext=q;

Теперь рассмотрим удаление из списка (list deletion). Нетрудно удалить элемент, стоящий сразу за pp. Эта операция показана здесь вместе с повторной вставкой удалённого элемента в начало другого списка (обозначенного переменной q). Здесь имеет место циклический обмен значений трёх указателей.

r = pnext; pnext = rnext; rnext = q; q = r;

Удаление самого элемента, на который указывает ссылка (а не следующего), труднее, так как здесь возникает та же проблема, что и со вставкой: невозможно просто так перейти назад от элемента к предшествующему.

Но удаление следующего элемента после копирования его значения вперёд - довольно очевидное и простое решение. Его можно применить, когда за pp стоит некоторый элемент, то есть pp не является последним элементом в списке. Однако необходимо гарантировать, что нет других переменных, ссылающихся на удаляемый элемент.

Обратимся теперь к фундаментальной операции прохода по списку. Предположим, что для каждого элемента списка, у которого первый элемент pp, нужно выполнить некоторую операцию Р(х). Эту задачу можно выполнить так:

WHILE (список, на который ссылается р, не пуст)

{

выполнить операцию Р;

перейти к следующему элементу;

}

Из определения оператора while и структуры связей следует, что Р применяется ко всем элементам списка и ни к каким другим.

Очень часто используемая со списками - поиск в списке элемента с заданным ключом.

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

Упорядоченные списки

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

Если список упорядочен (скажем, по возрастанию ключей), то поиск может быть прекращен, как только встретился первый ключ, больший нового. Упорядочение списка достигается вставкой новых элементов в надлежащем месте, а не в начале списка. При этом упорядоченность получается практически бесплатно. Это достигается благодаря легкости вставки элемента в связный список, то есть благодаря полному использованию его гибкости. Такой возможности нет ни при работе с массивами, ни с последовательностями. (Однако заметим, что даже упорядоченные списки не дают возможности реализовать аналог двоичного поиска для массивов.)

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

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

2. Описание основных понятий и механизмов ООП

Объекты

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

· понимание прикладной задачи (проблемы);

· введение основы для реализации на компьютере.

· Объект - это мыслимая или реальная сущность, обладающая характерным поведением, отличительными характеристиками и являющаяся важной в предметной области.

· Каждый объект имеет состояние, обладает некоторым хорошо определенным поведением и уникальной идентичностью.

Каждый программный объект имеет некоторый набор данных и некоторый программный код для обработки этих данных. Объект: данные «+» код.

Классы

Формально класс - шаблон поведения объектов определенного типа с определенными параметрами, определяющими состояние.

Все объекты одного и того же класса описываются одинаковыми наборами атрибутов. Однако объединение объектов в классы определяется не наборами атрибутов, а семантикой.

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

Все экземпляры одного класса (объекты, порожденные от одного класса)

· Имеют один и тот же набор свойств

· Общее поведение, одинаково реагируют на одинаковые сообщения

Инкапсуляция

Инкапсуляция (encapsulation) - это сокрытие реализации класса и отделение его внутреннего представления от внешнего (интерфейса). При использовании объектно-ориентированного подхода не принято использовать прямой доступ к свойствам какого-либо класса из методов других классов. Для доступа к свойствам класса принято использовать специальные методы этого класса для получения и изменения его свойств.

Внутри объекта данные и методы могут обладать различной степенью открытости (или доступности).

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

Агрегация

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

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

Обобщение моделирует отношение типа «общее-частное».

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

Наследование

Наследование (inheritance) - это отношение между классами, при котором класс использует структуру или поведение другого (одиночное наследование) или других (множественное наследование) классов. Наследование вводит иерархию «общее / частное», в которой подкласс наследует от одного или нескольких более общих суперклассов. Подклассы обычно дополняют или переопределяют унаследованную структуру и поведение.

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

Производный класс включает в себя:

1) Унаследованные свойства и методы (их определять не надо);

2) Новые свойства и методы, отсутствующие в исходном классе, за счёт чего дочерний класс имеет больше свойств и методов по сравнению с его родителями и поэтому описывает более конкретное понятие.

Дополнительно есть возможность видоизменить (переопределить) некоторые из унаследованных родительских методов.

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

Полиморфизм

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

Основные реализации полиморфизма в ООП:

1) Полиморфные (виртуальные) методы;

2) Полиморфные объектные указатели;

Переопределение (overriding) методов - это возможность объявления в дочерних классов методов, заголовки которых полностью совпадают с базовым родительским методом, но этим методам в дочерних классах даётся своя программная реализация.

Полное совпадение заголовков - это совпадение имён методов, количества, порядка и типов формальных параметров.

Полиморфные методы - это методы, которые в разных классах некоторой иерархии имеют одинаковые заголовки, но разную программную реализацию.

Полиморфизм применительно к объектным переменным означает возможность использования одной и той же переменной для доступа к объектам разных классов. Если объектная переменная объявлена с классовым типом BaseClass, то она имеет право адресовать объекты любых классов, производных от класса BaseClass.

Описание всех разработанных классов (Объектная реализация контейнера на основе комбинированной структуры «Динамический упорядоченный список массивов-стеков», язык реализации С++)

1) Первый класс, класс Apartment (класс квартир). Необходимые данные для объекта: номер квартиры, площадь квартиры. Значит класс Apartment будет иметь два поля: номер квартиры - Number, площадь квартиры - Area. Методы класса: конструктор без параметров Apartment () служит для динамического выделения памяти под объект, конструктор с входными параметрами Apartment (int N, float S) выделяет память под объект и инициализирует поля данных, деструктор, методы доступа к полям. Метод getNumber возвращает значение поля Number; метод getArea возвращает значение поля Area; метод setNumber задаёт значение поля Number, в качестве входного параметра принимает целочисленный тип; метод setArea задаёт значение поля Area, в качестве входного параметра принимает вещественный тип.

class Apartment // класс квартир

{

private:

int *Number; // номер квартиры

float *Area; // площадь квартиры

public:

Apartment();

Apartment (int N, float S);

~Apartment();

int getNumber(); // получаем номер квартиры

float getArea(); // получаем площадь квартиры

void setNumber (int N); // задаём номер квартиры

void setArea (float S); // задаём площадь квартиры

};

Apartment: Apartment()

{

Number=new int(0);

Area=new float(0);

}

 // -

Apartment: Apartment (int N, float S)

{

Number=new int(N);

Area=new float(S);

}

 // -

Apartment:~Apartment()

{

delete Area;

Area=0;

delete Number;

Number=0;

}

 // -

int Apartment:getNumber()

{

return *Number;

}

 // -

float Apartment:getArea()

{

return *Area;

}

 // -

void Apartment:setNumber (int N)

{

*Number=N;

}

 // -

void Apartment:setArea (float S)

{

*Area=S;

}

2) Второй класс StackOfApartments - это стек на основе массива, элементами которого являются объекты класса Apartment. В качестве полей содержит массив указателей на объекты класса Apartment, указатель на тип int - Spoint, указывающий на вершину стека, служебное поле - указатель на тип int - ShowSpoint, для отображения состояния стека, указатель на тип int - Count, количество элементов. Методы класса: конструктор, деструктор, методы для добавления, удаления и просмотра элементов, методы для проверки возможности добавления, удаления и просмотра элементов.

Конструктор без параметров StackOfApartments() служит для динамического выделения памяти под объект. Метод getCount возвращает значение поля Count-количество элементов. Метод Push служит для добавления нового элемента в стек, в качестве входных параметров получает целое число для инициализации поля Number, вещественное число для инициализации поля Area объекта класса Apartment. Метод Pop служит для удаления элемента с вершины стека. Методы Show и ShowAll служат для показа вершины стека и всех элементов стека соответственно, возвращают указатели на объекты типа Apartment. Метод DelAll служит для удаления всех элементов структуры. Метод checkShowAll служит для проверки перед вызовом функции ShowAll, используется как условие в цикле while, тип возвращаемого значения bool (true-можно показать). Метод checkAdd проверяет возможность добавления нового элемента в стек, возвращает true, если можно добавить. Метод CheckDel проверяет возможность удаления элемента из стека, возвращает true, если можно удалить.

const int max=400;

class StackOfApartments // стек квартир на основе массива

{

protected:

Apartment * flats[max];

int *SPoint; // индекс вершинного+1 элемента стека в // массиве=количество элементов

int *ShowSPoint; // индекс элемента для показа

int *Count;

public:

StackOfApartments();

~StackOfApartments();

void Push (int N, float S); // добавление элемента

void Pop(); // удаление элемента

Apartment * Show(); // показ вершины

Apartment * ShowAll(); // показ всех элементов стека поочередно

void DelAll(); // удаление всех элеметов

bool checkShowAll(); // проверка перед каждым вызовом ShowAll()

bool checkAdd(); // проверка перед добавлением

bool CheckDel(); // проверка перед удалением

int getCount(); // количество элементов

};

StackOfApartments: StackOfApartments()

{

SPoint=new int(0);

ShowSPoint=new int(0);

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

{

flats[i]=0;

}

Count=new int(0);

}

 // -

StackOfApartments:~StackOfApartments()

{

int x=*SPoint;

while (-x>=0)

{

flats[x]->~Apartment();

}

delete SPoint;

SPoint=0;

delete ShowSPoint;

ShowSPoint=0;

delete Count;

Count=0;

}

 // -

void StackOfApartments: Push (int N, float S)

{

flats[*SPoint]=new Apartment (N, S);

(*SPoint)++;

*ShowSPoint=*SPoint;

(*Count)++;

}

 // -

void StackOfApartments: Pop()

{

(*SPoint) -;

flats[*SPoint]->~Apartment();

flats[*SPoint]=0;

*ShowSPoint=*SPoint;

(*Count) -;

}

 // -

Apartment * StackOfApartments: Show()

{

int x=*SPoint;

int q=flats[-x]->getNumber();

float qq=flats[x]->getArea();

Apartment *tmp=new Apartment (q, qq);

return tmp;

}

 // -

Apartment * StackOfApartments: ShowAll()

{

Apartment *n=flats[- (*ShowSPoint)];

int q=n->getNumber();

float qq=n->getArea();

Apartment *tmp=new Apartment (q, qq);

return tmp;

}

 // -

void StackOfApartments: DelAll()

{

delete flats[- (*SPoint)];

(*Count) -;

}

 // -

bool StackOfApartments:checkShowAll()

{

bool p; //true-можно показать

if (*ShowSPoint!=0)

{

p=true;

}

else if (*ShowSPoint==0)

{

p=false;

*ShowSPoint=*SPoint;

}

return p;

}

 // -

bool StackOfApartments:checkAdd()

{

bool p; //true-можно добавить

if (*SPoint==max)

{

p=false;

}

else

{

p=true;

}

return p;

}

 // -

bool StackOfApartments: CheckDel()

{

bool p; //true-можно удалить

if (*SPoint==0)

{

p=false;

}

else

{

p=true;

}

return p;

}

 // -

int StackOfApartments:getCount()

{

return *Count;

}

 // -

3) Третий класс ApartmentHouse (класс домов) получаем, используя механизм наследования. Наследуем его от класса StackOfApartments. В новом классе добавляем новые свойства: номер дома Number, указатель на объект типа ApartmentHouse - указатель на следующий элемент списка (самоадресация). Новые методы класса: конструктор, деструктор, методы доступа к полю Number, методы доступа к полю Next.

Конструктор класса в качестве входного параметра принимает целое число для инициализации поля Number, затем вызывает конструктор родительского класса. Деструктор использует вспомогательный указатель на объекты типа StackOfApartments для вызова деструктора соответствующего класса. Метод setNumber задаёт значение поля Number, в качестве входного параметра принимает целое число. Метод getNumber возвращает значение поля Number, тип целый. Метод setNext задаёт значение поля Next, в качестве входного параметра принимает указатель на объект типа ApartmentHouse. Метод getNext возвращает значение поля Next, указатель на объект типа ApartmentHouse.

class ApartmentHouse:public StackOfApartments // класс домов

{

private:

int *Number; // номер дома

ApartmentHouse *Next; // указатель на следующий элемент списка

public:

ApartmentHouse (int N):StackOfApartments()

{Number=new int(N); Next=0;}

~ApartmentHouse();

int getNumber(); // получить номер дома

void setNumber (int N); // задать номер дома

void setNext (ApartmentHouse *next);

ApartmentHouse * getNext();

};

 // -

ApartmentHouse:~ApartmentHouse()

{

delete Number;

Number=0;

Next=0;

}

 // -

int ApartmentHouse:getNumber()

{

return *Number;

}

 // -

void ApartmentHouse:setNumber (int N)

{

*Number=N;

}

 // -

void ApartmentHouse:setNext (ApartmentHouse *next)

{

Next=next;

}

 // -

ApartmentHouse * ApartmentHouse:getNext()

{

return Next;

}

4) Четвёртый класс ManagementCompany (управляющая компания) - динамический упорядоченный список. Поля класса: счётчик числа элементов Count, указатели на объекты типа ApartmentHouse на заголовок списка(head), служебное поле - указатель Current на объекты типа ApartmentHouse для прохода по списку, указатель на объект библиотечного класса string (свойство Name-название управляющей компании), указатель на bool-flag, показывающий, производились какие-либо действия над объектом или нет. Методы класса: конструктор, деструктор; добавление, удаление элементов; поиск заданного элемента, проход по списку, проверки, методы доступа к полю Name, добавление и удаление элементов из заданных стеков.

Конструктор ManagementCompany без параметров для динамического выделения памяти под объект. Конструктор класса ManagementCompany с входными параметрами принимает ссылку на объект библиотечного класса string, для инициализации поля Name. Метод search служит для поиска заданного элемента, в качестве входного параметра принимает целое (поиск происходит по номерам домов), возвращает указатель на объект класса (копия искомого элемента структуры) ApartmentHouse. Метод Add служит для добавления нового элемента в список, в качестве входного параметра принимает целое, для инициализации у добавляемого элемента поля Number. Упорядочивание списка по номерам домов происходит при добавлении нового элемента.

Метод Del удаляет заданный элемент из списка, в качестве входного параметра принимает целое (номер удаляемого элемента). Метод pass необходим для прохода по списку, возвращает указатель на объекты (копии очередного элемента структуры) класса ApartmentHouse. Функция checkDel служит для проверки возможности удаления элемента из списка, тип возвращаемого значения bool (true-можно удалить). Метод checkpass служит для проверки возможности дальнейшего прохода по списку, тип возвращаемого значения bool (true-можно осуществить переход к следующему). Метод setName задаёт имя управляющей компании, в качестве входного параметра принимает ссылку на объект библиотечного класса string, с помощью метода getName получаем имя компании, функция возвращает объект класса string. Метод getflag возвращает значение поля flag, метод setflag задаёт значение поля flag. Метод getCount возвращает значение поля Count. Метод AddAp позволяет добавить в заданный элемент списка(дом) объект Apartment, входные параметры: целый тип-nAH - номер дома, целый тип-nA - номер квартиры, вещественный тип-S - площадь квартиры.

Возвращает 0, если дом с номером nAH отсутствует, иначе возвращает 1. Метод DelAp позволяет удалить из заданного элемента списка(дома) объект Apartment, если тот находится на вершине стека, входные параметры: целый тип-nAH - номер дома, целый тип-nA - номер квартиры. Возвращает 0, если дом с номером nAH отсутствует или поле Number вершинного элемента стека не равно nA, иначе возвращает 1.

 // -

class ManagementCompany // динамический упорядоченный список (управляющая компания)

{

private:

int *Count; // счётчик числа элементов

ApartmentHouse *head;

ApartmentHouse *Current; // вспомогательный указатель для прохода по списку

string *Name; // название управляющей компании

bool *flag;

public:

void setName (string &name); // ввод имени

string& getName(); // посмотреть имя

bool getflag();

void setflag (bool p);

ManagementCompany();

ManagementCompany (string &name); // конструктор

~ManagementCompany(); // деструктор

int getCount();

ApartmentHouse * search (int N); // поиск заданного элемента (поиск дома по его номеру)

int Add (int n); // добавление нового элемента в список, возвращает 0, если дом с номером n существует

 // упорядочивание списка по номерам домов происходит при добавлении нового элемента

void Del (int n); // удаляем элемент из списка

bool checkDel();

ApartmentHouse * pass(); // проход по списку

bool checkpass(); // проверка перед каждым вызовом pass()

int AddAp (int nAH, int nA, float s); // добавление квартиры в заданный дом, возвращает 0, если дом с номером n существует

int DelAp (int nAH, int nA); // удаление квартиры из заданного дома (c вершины стека, возвращает 0, если дом с номером n существует

);

 // -

ManagementCompany: ManagementCompany()

{

Count=new int(0);

head=new ApartmentHouse(0);

head->setNext(0);

Current=head;

Name=new string(«»);

flag=new bool(false);

}

 // -

ManagementCompany: ManagementCompany (string &name)

{

Count=new int(0);

head=new ApartmentHouse(0);

head->setNext(0);

Current=head;

Name=new string(name);

flag=new bool(false);

}

 // -

ManagementCompany:~ManagementCompany()

{

delete Count;

Current=head->getNext();

while (Current!=0)

{

ApartmentHouse *tmp=Current->getNext();

Current->~ApartmentHouse();

Current=tmp;

}

Current=0;

delete Name;

Name=0;

delete flag;

flag=0;

}

 // -

void ManagementCompany:setName (string &name)

{

Name=new string(name);

*flag=true;

}

 // -

string& ManagementCompany:getName()

{

string *tmp=new string(*Name);

return *tmp;

}

 // -

int ManagementCompany: Add (int n)

{

*flag=true;

int x=0;

if (head->getNext()==0)

{

ApartmentHouse *tmp=new ApartmentHouse(n);

head->setNext(tmp);

(*Count)++;

x=1;

}

else

{

ApartmentHouse *w1=head->getNext();

ApartmentHouse *w2=head;

while (w1!=0&&w1->getNumber()<n)

{

w2=w1;

w1=w1->getNext();

}

if (w1==0)

{

ApartmentHouse *tmp=new ApartmentHouse(n);

w2->setNext(tmp);

(*Count)++;

x=1;

}

else if (w1->getNumber()>n)

{

ApartmentHouse *tmp=new ApartmentHouse(n);

w2->setNext(tmp);

tmp->setNext(w1);

(*Count)++;

x=1;

}

}

return x;

}

 // -

void ManagementCompany: Del (int n)

{

*flag=true;

ApartmentHouse *w1=head->getNext();

ApartmentHouse *w2=head;

while (w1!=0)

{

if (w1->getNumber()==n)

{

w2->setNext (w1->getNext());

w1->~ApartmentHouse();

(*Count) -;

break;

}

else

{

w2=w1;

w1=w1->getNext();

}

}

}

 // -

bool ManagementCompany:checkDel()

{

bool p;

if (head==0)

{

p=false;

}

else if (head!=0)

{

p=true;

}

return p;

}

 // -

ApartmentHouse * ManagementCompany:search (int N)

{

ApartmentHouse *w1=head->getNext();

ApartmentHouse *TMP=0;

ApartmentHouse *qqq=0;

while (w1!=0)

{

if (w1->getNumber()==N)

{

TMP=new ApartmentHouse (w1->getNumber());

qqq=new ApartmentHouse (w1->getNumber());

while (w1->checkShowAll())

{

Apartment *tt=w1->ShowAll();

qqq->Push (tt->getNumber(), tt->getArea());

}

while (qqq->checkShowAll())

{

Apartment *tt=qqq->ShowAll();

TMP->Push (tt->getNumber(), tt->getArea());

}

break;

}

else

{

w1=w1->getNext();

}

}

return TMP;

}

 // -

ApartmentHouse * ManagementCompany:pass()

{

ApartmentHouse *q=Current->getNext();

Current=q;

ApartmentHouse *TMP=new ApartmentHouse (q->getNumber());

ApartmentHouse *qqq=new ApartmentHouse (q->getNumber());

while (q->checkShowAll())

{

Apartment *tt=q->ShowAll();

qqq->Push (tt->getNumber(), tt->getArea());

}

while (qqq->checkShowAll())

{

Apartment *tt=qqq->ShowAll();

TMP->Push (tt->getNumber(), tt->getArea());

}

return TMP;

}

 // -

bool ManagementCompany:checkpass()

{

bool p;

if (Current->getNext()!=0)

{

p=true;

}

else

{

p=false;

Current=head;

}

return p;

}

 // -

int ManagementCompany: AddAp (int nAH, int nA, float s)

{

*flag=true;

int x=0;

ApartmentHouse *w1=head->getNext();

ApartmentHouse *tmp=0;

while (w1!=0)

{

if (w1->getNumber()==nAH)

{

tmp=w1;

break;

}

else

{

w1=w1->getNext();

}

}

if (tmp!=0)

{

tmp->Push (nA, s);

x=1;

}

return x;

}

 // -

int ManagementCompany: DelAp (int nAH, int nA)

{

*flag=true;

int x=0;

ApartmentHouse *w1=head->getNext();

ApartmentHouse *tmp=0;

while (w1!=0)

{

if (w1->getNumber()==nAH)

{

tmp=w1;

break;

}

else

{

w1=w1->getNext();

}

}

if (tmp!=0)

{

if (tmp->CheckDel())

{

if (tmp->Show()->getNumber()==nA)

{

tmp->Pop();

x=1;

}

}

}

return x;

}

 // -

int ManagementCompany:getCount()

{

return *Count;

}

 // -

bool ManagementCompany:getflag()

{

return *flag;

}

void ManagementCompany:setflag (bool p)

{

*flag=p;

}

 // -

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

На главной форме демонстрационного модуля располагаются такие стандартные компоненты как: Button, Edit, Label, GroupBox, ComboBox, CheckListBox, ListBox, MainMenu, OpenDialog и SaveDialog.

Компонент Button представляет собой стандартную кнопку Windows, инициирующую какое-то действие. Основное с точки зрения внешнего вида свойство кнопки - Caption (надпись).

Основное событие кнопки - OnClick, возникающее при щелчке на ней. В обработчике этого события записываются операторы, которые должны выполняться при щелчке пользователя на кнопке.

Свойство Cancel, если его установить в true, определяет, что нажатие пользователем клавиши Esc будет эквивалентно нажатию на данную кнопку.

Свойство Default, если его установить в true, определяет, что нажатие пользователем клавиши ввода Enter будет эквивалентно нажатию на данную кнопку, даже

если данная кнопка в этот момент не находится в фокусе. Правда, если в момент нажатия Enter в фокусе находится другая кнопка, то все-таки сработает именно кнопка в фокусе.

Из методов, присущих кнопкам, имеет смысл отметить один - Click. Выполнение этого метода эквивалентно щелчку на кнопке, т.е. вызывает событие кнопки

OnClick.

В компоненте Edit вводимый и выводимый текст содержится в свойстве Text.

Это свойство можно устанавливать в процессе проектирования или задавать программно. Выравнивание текста невозможно. Перенос строк тоже невозможен.

Текст, не помещающийся по длине в окно, просто сдвигается, и пользователь может перемещаться по нему с помощью курсора. Свойство AutoSize позволяет автоматически подстраивать высоту (но не ширину) окна под размер текста. Свойство Font определяет атрибуты шрифта. Свойство Text-текст в окне редактирования.

Метод void Clear(void) удаляет текст из окна.

Компонент Label используется для отображения текста, который играет роль метки и не изменяется пользователем. Текст метки задается свойством Caption.

Шрифт надписи определяется свойством Font, цвет фона - свойством Col or, а цвет надписи - подсвойством Color свойства Font. Размер меток Label определяется свойством AutoSize. Если это свойство установлено в true, то вертикальный и горизонтальный размеры компонента определяются размером надписи. Если же

AutoSize равно false, то выравнивание текста внутри компонента определяется свойством Alignment, которое позволяет выравнивать текст по левому краю, правому краю или центру клиентской области метки.

Панель GroupBox - это контейнер с рамкой и надписью, объединяющий группу связанных органов управления, таких как радиокнопки RadioButton, индикаторы CheckBox и т.д. В отличие от других панелей (например, Panel) не имеет широких возможностей задания различных стилей оформления. Но GroupBox имеет встроенную рамку с надписью, которая обычно используется для выделения на форме группы функционально объединенных компонентов. Свойство Caption - надпись в углу рамки панели. Свойство Font определяет атрибуты шрифта.

Компонент ComboBox объединяет функции компонетов ListBox - спи ка, и Edit - окна редактирования. Компонент позволяет пользователю выбрать из списка необходимую строку или задать в качестве выбора собственный текст. Список может отображаться в развернутом виде или как выпадающий список.

Отличие ComboBox от схожего по функциям компонента ListBox заключается в следующем:

* ComboBox разрешает пользователю редактировать список, a ListBox не разрешает

* в ComboBox список может быть развернут или свернут, а в ListBox он всегда развернут

* ListBox может допускать множественный выбор, а в ComboBox пользователь всегда должен выбрать только один элемент

Основное свойство компонента, содержащее список строк, - Items, имеющее тип TStrings. Во время выполнения работать с этим свойством можно, пользуясь свойствами и методами класса

TStrings - Clear, Add и другими.

Стиль изображения списка определяется свойством Style.

Компонент CheckListBox аналогичен компоненту списка строк ListBox. за исключением того, что рядом с каждый элементом находится окно с флажком - индикатор, который пользователь может включать и выключать, помечая элементы

списка. Состояние индикатора изменяется при каждом щелчке пользователя на нем.

Основное свойство компонента, содержащее список строк, - Items, имеющее тип TStrings. Заполнить его во время проектирования можно, нажав кнопку с многоточием около этого свойства в окне Инспектора Объектов. Во время выполнения работать с этим свойством можно, пользуясь свойствами и методами класса TStrings - Clear, Add и другими.

Индекс выбранной пользователем строки определяется свойством Itemlndex, доступным только во время выполнения. Если ни одна строка не выбрана, то

Itemlndex = -1. Начальное значение Itemlndex невозможно задать во время проектирования. По умолчанию Itemlndex = -1. Это означает, что ни один элемент списка не выбран.

Свойство Sorted позволяет упорядочить список по алфавиту. При Sorted = true новые строки в список добавляются не в конец, а по алфавиту.

Состояния индикаторов определяют два свойства: State и Checked. Оба эти свойства можно рассматривать как индексированные массивы, каждый элемент которого соответствует индексу строки. Эти свойства можно устанавливать программно или читать, определяя установки пользователя.

В компоненте CheckListBox имеется событие OnClickCheck, возникающее при каждом изменении пользователем состояния индикатора. Его можно использовать для обработки результатов изменения.

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

Отличие ListBox от схожего по функциям компонента ComboBox заключается в следующем:

* ComboBox разрешает пользователю редактировать список, a ListBox не разрешает

* в ComboBox список может быть развернут или свернут, а в ListBox он всегда развернут

* ListBox может допускать множественный выбор, а в ComboBox пользователь всегда должен выбрать только один элемент

Основное свойство компонента, содержащее список строк, - Items, имеющее тип TStrings. Заполнить его во время проектирования можно, нажав кнопку с многоточием около этого свойства в окне Инспектора Объектов. Во время выполнения работать с этим свойством можно, пользуясь свойствами и методами класса TStrings - Clear, Add и другими.

Компонент MainMenu отображает на форме главное меню. Обычно на форму помещается один компонент MainMenu. В этом случае его имя автоматически заносится в свойство формы Menu.

Основное свойство компонента - Items. Его заполнение производится с помощью конструктора меню, вызываемого двойным щелчком на компоненте Main-Menu или нажатием кнопки с многоточием рядом со свойством Items. при выборе нового раздела вы увидите в Инспекторе Объектов множество свойств данного раздела. Дело в том, что каждый раздел меню, т.е. каждый элемент свойства Items, является объектом типа TMenuItem, обладающим своими свойствами, методами, событиями.

Свойство Caption обозначает надпись раздела. Заполнение этого свойства подчиняется тем же правилам, что и заполнение аналогичного свойства в кнопках.

Свойство Name задает имя объекта, соответствующего разделу меню.

Компоненты OpenDialog и SaveDialog вызывают стандартные диалоги Windows открытия и сохранения файлов. Открытие соответствующего диалога осуществляется методом Execute. Если в диалоге пользователь нажмет кнопку Открыть (Сохранить), диалог закрывается, метод Execute возвращает true и выбранный файл отображается в свойстве компонента-диалога FileName. Если же пользователь отказался от диалога (нажал кнопку Отмена или клавишу Esc), то метод Execute возвращает false. Типы искомых файлов, появляющиеся в диалоге в выпадающем списке Тип, задаются свойством Filter. В процессе проектирования это свойство проще всего задать с помощью редактора фильтров.

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

В центральной части главной формы в компоненте CheckListBox1 отображается список всех имеющихся домов, упорядоченный по возрастанию их номеров. При выборе какой-либо строки из CheckListBox1, в компоненте ListBox2 отображаются квартиры выбранного дома, а в компоненте ListBox3 площади (номер и площадь одной квартир выводятся в строках с одинаковыми номерами в компонентах ListBox2 и ListBox3). В компонент Label4 выводится номер дома, выбранного в CheckListBox1.

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

В верхней части формы располагается компонент MainMenu. С помощью вкладок меню можно осуществить следующие действия: открыть, создать, сохранить, закрыть файл или закрыть саму программу. Если во время работы программы над данными производились какие-либо действия, то при попытке осуществить какие-нибудь действия с помощью вкладок меню появится диалоговое окно, предоставляющее возможность сохранить данные.

4. Описание структуры проекта

Проект представляет собой набор программных единиц - модулей. Данный проект состоит из трёх модулей.

Один из модулей, называемый главным, содержит инструкции, с которых начинается выполнение программы(Unit7), второй модуль(Unit8) - объявление всех разработанных классов с реализацией их методов, третий модуль(OKCANCL2) - диалоговое окно.

К главному модулю подключены файлы из стандартной библиотеки С++: fstream, iostream - для файлового ввода-вывода, string - для работы с объектами библиотечного класса string. Также подключены заголовочные файлы двух остальных модулей. Прописаны прототипы функций для сохранения данных на диск и обратной загрузки. Объявлены глобальные переменные целого типа: SWITCH - служит для переключение между различными вариантами действий в кнопках «да» и «нет» диалогового окна (сохранение данных), LB1и LB2 - содержат значение номера дома, который отображают компоненты Lisbox1 и Lisbox2, Lisbox3, необходимы компонентов, если дом с номером LB1 и(или) LB2 удалён; CLEAR - указывает на необходимость очистки компонентов ввода / вывода при открытии, создании и закрытии файла; P - служит для проверки успешности открытия файла. Указатель Current на объект класса ManagmentCompany - контейнер «Управляющая компания», с которым работает пользователь.

void __fastcall TForm7:N2Click (TObject *Sender) // вкладка меню-создать

{

if (Current!=0) // если контейнер создан

{

if (Current->getflag()) // если выполнялись действия над данными

{

SWITCH=2;

OKRightDlg->ShowModal(); // открытие диалогового окна

if (CLEAR!=0) // проверка необходимости очищения компонентов

{

CLEAR=0;

Edit1->Clear();

ListBox2->Clear();

CheckListBox1->Clear();

Edit4->Clear();

...

Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.