- •Раздел 4. Разработка по Тема 4.1. Проектирование интерфейса с пользователем
- •4.1.1. Типы пользовательских интерфейсов.
- •4.1.2. Пользовательская и программная модели интерфейса.
- •4.1.3. Разработка диалогов.
- •4.1.4. Основные компоненты графических пользовательских интерфейсов.
- •Тема 4.2. Реализация графических пользовательских интерфейсов.
- •4.2.1. Диалоги, управляемые пользователем.
- •4.2.2. Диалоги, управляемые системой.
- •4.2.3. Использование метафор.
- •4.2.4. Технология Drag and Drop.
- •4.2.5. Интеллектуальные элементы.
- •4.3.1. Базовые типы данных.
- •Константы
- •Область действия имен
- •4.3.2. Указатели и адресная арифметика.
- •4.3.3. Составные типы данных. Структуры
- •Битовые поля
- •Определение типов
- •Перечислимые типы
- •4.3.4. Выражения и операции.
- •4.3.5. Управляющие конструкции. Условные операторы
- •Операторы циклов
- •4.4.1. Статические одномерные массивы.
- •4.4.2. Статические многомерные массивы.
- •4.4.3. Динамические массивы.
- •4.4.4. Массивы указателей.
- •4.5.1. Стеки.
- •4.5.2. Очереди.
- •4.5.3. Списки.
- •4.5.4. Бинарные деревья.
- •4.6.1. Объявление классов и экземпляров классов.
- •4.6.2. Инкапсуляция данных и методов.
- •4.6.3. Конструкторы классов.
- •Конструктор по умолчанию
- •Конструктор копирования
- •4.6.4. Деструкторы классов.
- •4.7.1. Разделы в описании класса.
- •4.7.2. Friend-конструкции.
- •4.7.3. Статические члены классов.
- •4.7.4. Использование описателя const в классах.
- •4.8.1. Вложенность классов.
- •4.8.2. Наследование данных и методов.
- •4.8.3. Типы наследования.
- •4.9.1. Полиморфизм раннего связывания.
- •4.9.2. Полиморфизм позднего связывания и виртуальные функции.
- •4.9.3. Абстрактные методы и классы.
- •4.10.1. Функции консольного ввода-вывода.
- •4.10.2. Функции файлового ввода-вывода.
- •4.10.3. Использование библиотеки классов потокового ввода-вывода.
- •4.11.1. Перегрузка операций.
- •4.11.2. Шаблоны функций.
- •4.11.3. Шаблоны классов.
- •4.11.4. Обработка исключений.
- •Тема 4.12. Com-технология.
- •4.12.1. Основные понятия.
- •4.12.2. Типы интерфейсов.
- •Свойства интерфейсов
- •Типы интерфейсов
- •4.12.3. Типы com-объектов.
- •4.12.4. Фабрика классов.
- •Тема 4.13. Построение com-сервера.
- •4.13.1. Язык idl.
- •Содержимое файла idl
- •4.13.2. Определение пользовательского интерфейса.
- •4.13.3. Реализация пользовательского интерфейса.
- •4.13.4. Создание тестового клиента.
- •Тема 4.14. Обзор платформы ms .Net.
- •4.14.1. Общая идея архитектуры .Net.
- •4.14.2. Достоинства и недостатки .Net.
- •4.14.3. Схема трансляции программ в .Net.
- •4.14.4. Язык msil.
- •4.14.5. Объектно-ориентированная модель .Net.
4.5.2. Очереди.
Очередью называется упорядоченный набор элементов, которые могут удаляться с одного ее конца (называемого началом очереди) и помещаться в другой конец этого набора (называемого концом очереди) (рис. 5.5).
Ее также называют структурой данных, организованной по принципу FIFO (First In First Out, первый вошел — первым вышел). Как и для стека, максимальное число элементов в очереди не должно лимитироваться используемым программным обеспечением: память должна запрашиваться и освобождаться динамически по мере того, как в очередь добавляются новые, и из нее удаляются находящиеся там элементы.
Базовые операции, выполняемые над очередью, очевидны:
insert — добавить в очередь новый элемент
remove — удалить из очереди первый элемент
Интерфейс с программами, обслуживающими очередь, приведен в листинге 5.4.
/* Интерфейс для работы с очередью */
#define QUEUE struct queue // [kju:]
QUEUE
{
int info;
QUEUE *next;
};
extern void insertItem(QUEUE **ppQueue, int nItem);
extern int removeItem(QUEUE **ppQueue, int *nError);
Представленные функции являются аналогами функций push и pop, применяемыми для работы со стеком, и все что говорилось там о передаче параметров и индикации ошибки, в полной мере относится и к представленным функциям.
Работу с очередью можно организовать двумя способами:
1. Используя дополнительные переменные для начала и конца очереди.
2. Используя переменную только для начала очереди, перемещаясь в конец на основе внутренних связей.
Какой из вариантов больше подходит вам — дело вкуса, мы же остановились на втором. Принципы работы с очередью продемонстрированы на рис. 5.6.
/* Реализация функций работы с очередью */
#include <malloc.h>
#include "queue.h"
void insertItem(QUEUE **ppQueue, int nItem)
{
QUEUE *pNewItem;
QUEUE *pCurItem = *ppQueue; // Текущий — начало очереди
QUEUE *pPreItem = 0;
while(pCurItem)
{
// Перемещаемся в конец очереди
pPreItem = pCurItem;
pCurItem = pCurItem->next;
}
// Запрашиваем память под структуру для элемента очереди
pNewItem = (QUEUE *)malloc(sizeof(QUEUE));
// Заполняем информационное поле
pNewItem->info = nItem;
if(pPreItem)
{
// Если очередь пуста, делаем новый элемент ее началом
pNewItem->next = 0;
pPreItem->next = pNewItem;
}
else
{
//В противном случае помещаем его в конец
*ppQueue = pNewItem;
(*ppQueue)->next = 0;
}
} int removeItem(QUEUE **ppQueue, int *nError) {
QUEUE *pOldItem = *ppQueue;
int nOldlnfo = 0;
if(*ppQueue)
{
// Если очередь не пустая — извлекаем элемент
nOldInfo = pOldItem->info;
*ppQueue = (*ppQueue)->next;
//и освобождаем память
free(pOldItem);
*nError = 0;
}
else
// В противном случае ошибка
*nError =1;
return nOldlnfo; }
Обратите внимание, что код функции removeItem полностью совпадает с кодом функции pop для стека, поэтому более подробно рассмотрим функцию insertItem.
Сначала создается локальная переменная *pCurItem, являющаяся указателем на структуру queue, которая инициализируется значением начала очереди — *ppQueue. Затем описывается локальная переменная *pPreItem того же типа, которая инициализируется значением 0. И наконец, создается локальная переменная для хранения адреса нового элемента очереди — *pNewItem.
Далее организуется просмотр очереди до достижения ее конца, после чего указатель pPreItem содержит адрес последнего элемента queue в очереди. Далее запрашивается память под новый элемент очереди pNewItem, полю Info этой структуры присваивается значение nItem. Если очередь не пуста, то полю next новой структуры присваивается значение 0, которое показывает, что это теперь последний элемент в очереди, а полю next бывшего последнего элемента присваивается значение адреса новой структуры pNewitem. Если же очередь пуста, то указатель на начало очереди принимает значение адреса нового элемента.
Мы рассмотрели простейший пример — линейную очередь. Помимо нее часто используется так называемая циклическая очередь, в которой последний элемент указывает на ее начало.