МУ_ДЗ_2014 (1079920), страница 6
Текст из файла (страница 6)
i = IntMas.GetAt(2);
cout << "i = "<< i << " IntMas[2] = " << IntMas[2] << endl;
Получим результат:
i = 2 IntMas[2] = 2
Метод SetAt позволяет заменить элемент в массиве на другой:
IntMas.SetAt(3, 10); // Значение элемента номер 3 заменяется на 10
for (i = 0 ; i < IntMas.GetCount() ; i++ )
cout << IntMas[i] << " " ; cout << endl;
Получим результат:
0 1 2 10 4
С помощью метода InsertAt можно добавить в середину:
IntMas.InsertAt(1, 100);
for (i = 0 ; i < IntMas.GetCount() ; i++ )
cout << IntMas[i] << " " ; cout << endl;
Получим результат:
0 100 1 2 10 4
С помощью метода RemoveAt можно удалить любой элемент по номеру:
IntMas.RemoveAt(2);
for (i = 0 ; i < IntMas.GetCount() ; i++ )
cout << IntMas[i] << " " ; cout << endl;
Получим результат:
0 100 2 10 4
С помощью метода IsEmpty можно проверить наличие в массиве элементов, а с помощью метода RemoveAll, удалить все элементы:
if ( IntMas.IsEmpty() )
{ cout << "Массив пуст!" <<endl; }
else
{ cout << "Массив не пуст!" <<endl; };
IntMas.RemoveAll(); // Удаление всех элементов
if ( IntMas.IsEmpty() )
{ cout << "Массив пуст!" <<endl; }
else
{ cout << "Массив не пуст!" <<endl; };
Получим результат:
Массив не пуст!
Массив пуст!
Методы SetSize и FreeExtra позволяют установить новую размерность массива и удалить свободную память:
IntMas.SetSize(32, 128); // Размер 32
cout << "GetSize = " << IntMas.GetSize() << endl;
cout << "GetUpperBound = " << IntMas.GetUpperBound() << endl;
IntMas.SetSize(10, 128); // Новый Размер 10
IntMas.FreeExtra();
cout << "GetSize = " << IntMas.GetSize() << endl;
cout << "GetUpperBound = " << IntMas.GetUpperBound() << endl;
Получим результат:
GetSize = 32
GetUpperBound = 31
GetSize = 10
GetUpperBound = 9
Специальными методами можно копировать (Copy) или добавлять к существующему массиву (Append) однотипные массивы:
CArray<int , int> IntMas1;
IntMas1.Add(55); // Добавим 1 элемент в массив IntMas1
IntMas1.Append( IntMas ); // Добавление массива IntMas с массиву IntMas1
for (i = 0 ; i < IntMas1.GetCount() ; i++ )
cout << IntMas1[i] << " " ; cout << endl;
IntMas.Copy( IntMas1 ); // Копирование массива IntMas1 в массив IntMas
for (i = 0 ; i < IntMas.GetCount() ; i++ )
cout << IntMas[i] << " " ; cout << endl;
Получим результат:
55 0 100 2 10 4
55 0 100 2 10 4
Для класса массивов CObArray все методы аналогичны. Существенное отличие заключается в том, что такой массив поддерживает массив указателей на объекты типа CObject, или точнее, объекты классов наследованных от CObject. В этом случае их описание эквивалентно такому:
CArray< CObject *, CObject*> mArr; // Нужна настройка шаблона на CObject
CObArray mArrObj; // Настройки шаблона не нужно
Если класс Point является наследником класса CObject, то все предыдущие фрагменты проверки работы методов для нашего класса объектов должны нормально функционировать, например:
class Point : public CObject { … };
…
for (i = 0 ; i < 5 ; i++ )
mArrObj.Add(new Point(i,i));
cout << " ";
for (i = 0 ; i < mArrObj.GetCount() ; i++ )
cout << *((Point *)(mArrObj[i])) << " " ; //явное приведение типа нужно для
// использования перегруженного метод вывода в поток
cout << endl;
Получим результат:
{ x = 0 y = 0 }
{ x = 1 y = 1 }
{ x = 2 y = 2 }
{ x = 3 y = 3 }
{ x = 4 y = 4 }
Единственное отличие состоит в необходимости преобразования указателя к типу Point для автоматического вызова перегруженной операции вывода. Кроме этого, необходимо учесть что добавление, выборка объектов должны выполняться с указанием объектов соответствующих типов, наследованных от класса CObject.
42 Контейнерные классы массивов в ATL
Контейнерный класс в библиотеке ATL называется CAtlArray. Он является шаблонным классом и имеет следующее формальное описание:
template< typename E, class ETraits = CElementTraits< E >
> class CAtlArray { … };
В этом классе все очень похоже на класс CArray из MFC, но некоторые методы отсутствуют. В частности недоступны методы: GetUpperBound, GetSize и SetSize. Все остальные методы и свойства совпадают с массивами библиотек MFC.
При подключении классов библиотеки ATL в главный модуль нужно добавить следующий заголовочный файл:
#include <atlcoll.h>
Для примера использования класса CAtlArray рассмотрим фрагмент программы с массивом целых чисел:
CAtlArray<int> atlMas;
…
for (i = 0 ; i < 5 ; i++ )
atlMas.Add(i);
for (i = 0 ; i < atlMas.GetCount() ; i++ )
cout << atlMas[i] << " " ;
cout << endl;
После выполнения этого фрагмента программы получим результат:
0 1 2 3 4
Если в предыдущих фрагментах программ удалить строки с недоступными функциями и заменить название массивов, они будут, несомненно, работать.
43 Контейнеры - списки
Контейнеры типа список обеспечивают работу с множеством объектов, число которых заранее неизвестно и может изменяться во время работы программы. Кроме того, порядок этих объектов может также изменяться, например, с добавлением новых объектов в произвольное место упорядоченного множества. Работа с массивами, особенно если их размерность велика, приводит к значительным временным затратам процессорного времени. Хотя прямого доступа к элементам списка не определяется (операция индексирования недоступна - просмотр списка возможет только последовательно), динамические возможности перемещения по списку, его изменения, поиска и сортировки выполняются значительно эффективнее, чем в массивах. Контейнерные объекты типа список применяются практически во всех программах средней и большой сложности. На основе списков строятся более сложные структуры данных: деревья, сетевые структуры данных и многие другие.
44 Навигация, позиции и ссылки на объекты
При доступе к элементам контейнера типа список отсутствует возможность указания индекса элемента, по сравнению с массивами. Для доступа к конкретному элементу используется специальный тип данных, задающий позицию, – POSITION. Переменная этого типа фактически является адресом элемента списка, который содержит объект. Специальные методы (GetHeadPosition GetTailPosition ,GetNext и GetPrev) позволяют перемещаться по списку в прямом и обратном направлении (такое перемещение с определением новой позиции похоже на работу итераторов). С помощью специальных методов на основе переменной типа позиция может быть выбран объект из списка (GetAt). Такая навигация характерна для классов: CList, CObList и CAtlList. В отличие от использования итераторов STL, которые по сути играют такую же роль, операции инкремента для позиций недоступны. Пример:
POSITION pos;
…
pos = IntList.GetHeadPosition(); // Установка позиции первого элемента списка IntList
cout << "IntList = " << IntList.GetAt(pos) << endl;
IntList.GetNext( pos); // Получение позиции следующего элемента
…
Если после выполнения операции значение pos становиться равным нулю (NULL), то это означает, что достигнут конец списка.
Методы доступа к элементам контейнера чаще возвращают ссылку на объект или сам объект, а не указатель на него. В этом случае необходимо предусматривать явное преобразование типов, например:
CObList PoList; // Список ссылок/ указателей на базовый класс CObject
…
cout << "PList = " << *((Point *)(PoList.GetAt(pos))) << endl; //Приведение типа
Первоначально полученный тип приводиться явно к указателю на класс Point, и только затем выполняется разыменование и получается объект.
45 Операции с контейнерами типа список
При работе с контейнерными объектами типа список можно выделить следующие основные операции (в скобках показанные названия методов):
-
Создание (описание) контейнеров, с указанием размерности контейнера и его заполнения (list, CAtlList, CList, CObList );
-
Добавление объектов в список (например: push_back , addHead, InsertAfter);
-
Удаление объектов из списка (например: pop_back , erase, RemoveAt);
-
Доступ к объектам списка (например: GetAt, GetHead, GetTail);
-
Очистка контейнера - списка (например: clear, erase, RemoveAll);
-
Получение числа элементных объектов в контейнере (например: size, GetSize, GetCount);
-
Поиск в списке (например: Find , FindIndex);
-
Проверка пустого (например: empty, IsEmpty)
-
Сортировка (например: sort, reverse)
-
Обмен местоположения объектов в контейнере (например: swap);
-
Операции над массивами (например: copy, append, assign);
-
Навигация по спискам (например: GetNex, GetPrev, GetHeadPosition, GetTailPosition);
-
Сравнение контейнеров (операции отношения контейнеров).
46 Контейнерные классы списков в STL (list)
В библиотеке STL описывается шаблонный класс list, который позволяет описывать списки переменных любого типа. Формальное определение шаблона дано ниже:
template <
class Type,
class Allocator=allocator<Type>
> class list{ … };
Для работы объектами этого класса необходимо подключить заголовочный файл:
#include < list >
Для описания списков предусмотрены разные конструкторы. Примеры описания списков даны ниже:
list <int> l0; // Пустой список l0
list <int> l1( 3 ); // Список с тремя элементами равными 0
list <int> l2( 5, 2 ); // Список из пяти элементов равными 2
list <int> l3(l2); // Список l3 на основе списка l2
list <int>::iterator l3_Iter; // Описания итератора
l3_Iter = l3.begin( ); //
l3_Iter++; l3_Iter++;
list <int> l4( l3.begin( ), l3_Iter ); // Новый список l4 на основе первых двух элементов L3
Для описания пустого списка l (типа list) нужно указать тип int:
list <int> l;
list<int>::iterator iter;
…
cout<< "Добавление:" << endl;
l.push_back( 1 ); // Добавление в конец списка
l.push_back( 2 ); // Добавление в конец списка
l.push_front( 5 ); // Добавление в начало списка
lPrint(l); // Собственная функция печати целого списка
Функцию печати опишем в заголовочном файле так, чтобы в ней в данной функции использован прямой итератор для класса list, а для индексации элементов списка вспомогательная целая переменная:
void lPrint(list<int>& l)
{
list<int>::iterator iter;
int i = 0;
if ( !l.empty() ) { // Проверка пустого списка
for( iter = l.begin(); iter != l.end() ; iter++ , i++)
{ cout << "l["<< i << "] = " << *iter << endl;} }
else
cout << "Список пуст!"<< endl;};
В данной функции используется итератор iter, который позволяет продвигаться по списку (iter++). Для установки итератора на первый элемент используется метод begin. Остановка просмотра проверяется методом end. Для проверки пустого списка используется метод empty. Для дальнейшей демонстрации возможностей списков будем использовать эту функцию. В первом фрагменте получим результат:
Добавление:
l[0] = 5
l[1] = 1
l[2] = 2
Перечень методов класса список приведен в разделе Справочные материалы, подробное описание методов вы можете найти в документации, литературе и справочной системе MSDN[5]. Рассмотрим еще несколько примеров использования объектов класса список и его методов. Для копирования списков может быть использован метод слияния (assign), а для очистки списка может быть использован метод удаления (clear):
// Копирование и очистка
list <int> l20;
lPrint(l);
l20.assign( l.begin( ), l.end( ) );
cout<< "После копирования l в l20:" << endl;