И.А. Волкова, А.В. Иванов, Л.Е. Карпов - Основы объектно-ориентированного программирования. Язык программирования С++ (ЧБ) (1114895), страница 17
Текст из файла (страница 17)
. .};template <class T> class X{// . . .public:friend void f1();// функция f1() является// дружественной ко всем// инстанцированиям// классаfriend Y<T> f2(Y<T> par1); // порождение функции f2()// для фактического типа T// является дружественной// только к тому// инстанцированию класса// X, которое подходит по// фактическому// типу–параметру.// . . .};95template <class T> Y<T> f2(Y<T> par1){ /* . . . */ }Статические члены создаются для каждого инстанцирования класса.Пример:template <class T> class X {static T x1;// .
. .};int X <int> :: x1 = 0;double X <double> :: x1 = 1.5;int main() {X <int> xx1;X <double> xx2;. . .return 0;}15.6.Эквивалентность типовПри объявлении объектов с использованием шаблона задаются фактическиепараметры типа. При задании одного и того же набора аргументов шаблона получается один и тот же тип объекта.Использование ключевого слова typedef задает новое имя (синоним) длятипа, никакой новый тип при этом не создается. При задании типа с использованием шаблонов эквивалентность типов проверяется с учетом синонимов(typedef).Пример:typedef unsigned int uint;template <class T, int s> class vect{ /* .
. . */ };int main(){vect <uint,16> v1;vect <unsigned int,16> v2;. . .}Объекты v1 и v2 имеют один и тот же тип.96Кроме того, эквивалентность типов определяется с точностью до вычисленияконстантных выражений на этапе компиляции. Поэтому объекты v1 и v3vect <uint,16> v1;vect <unsigned int,10+6> v3;имеют одинаковый тип.16.Стандартная Библиотека шаблонов STLSTL (Standard Template Library) является частью стандарта C++. Основныекомпоненты этой библиотеки – иерархии шаблонов классов и функций. Библиотека STL является важной составной частью стандартной библиотеки.Ядро STL состоит из четырех основных компонентов:-контейнерыитераторыалгоритмыраспределители памяти (аллокаторы)16.1.
КонтейнерыКонтейнер – тип данных (класс), предназначенный для хранения объектовкакого-либо типа (возможна реализация контейнера, который хранит объектыразных типов: в этом случае в нем хранятся указатели на базовый тип для всехжелаемых типов, то есть формально хранятся объекты одного типа, а фактическиуказатели ссылаются на элементы разных типов из одной иерархии классов).Примерами контейнеров являются массив, дерево, список.Стандартные контейнеры библиотеки STL• Vector < T >- динамический массив• List < T >- линейный список• Stack < T >- стек• Queue < T >- очередь• Deque < T >- двусторонняя очередь• Priority_queue < T > - очередь с приоритетами• Set < T >- множество• Bitset < N >- множество битов (массив из N бит)• Multiset < T >- набор элементов, возможно, одинаковых• Map < key, val >- ассоциативный массив• Multimap < key, val > - ассоциативный массив для хранения//пар «ключ–значение», где с каждым//ключом может быть связано более//одного значения.97Примечание.
Строго говоря, стек, очередь, очередь с приоритетами не считаютсястандартными контейнерами. Они построены с ограничениями функциональности набазе других контейнеров. Тем не менее, они включены в библиотеку STL наряду с другими стандартными контейнерами.В каждом классе-контейнере определен набор функций для работы с этимконтейнером, причем все контейнеры поддерживают стандартный набор базовыхопераций (функции, одинаково называющиеся, имеющие одинаковый профиль исемантику, их примерно 15-20).
Например, функция push_back() помещаетэлемент в конец контейнера, функция size() выдает текущий размер контейнера. Основные операции включаются в следующие группы:••••Доступ к элементуВставка элементаУдаление элементаИтераторыОперации, которые не могут быть эффективно реализованы для всех контейнеров, не включаются в набор общих операций.
Например, обращение по индексу введено для контейнера vector, но не для list.Каждый контейнер в своей открытой области содержит набор определенийстандартных имен типов. Среди них есть следующие имена:value_type- тип элемента,allocator_typesize_type- тип распределителя памяти,- тип, используемый для индексации,iterator, const_iterator- итератор,reverse_iterator, const_reverse_iterator- обратный итератор,pointer, const_pointer- указатель на элемент,reference, const_reference- ссылка на элемент.Эти имена определяются внутри каждого контейнера так, как это необходимодля соответствующего контейнера. При этом реальные типы инкапсулированы.Это позволяет писать программы с использованием контейнеров, не зависящие оттипов данных, реально используемых в контейнерах.16.2.
Распределители памятиКаждый контейнер имеет аргумент, называемый распределителем памяти(allocator), который используется при выделении памяти под элементы контейнера и предназначен для того, чтобы освободить разработчиков контейнеров, атакже алгоритмов, от подробностей физической организации памяти.Распределитель памяти обеспечивает стандартные способы выделения иперераспределения памяти, а также стандартные имена типов для указателей иссылок. Стандартная библиотека обеспечивает стандартный распределитель памяти.
Кроме того, можно задать свои распределители памяти, предоставляющие98альтернативный доступ к памяти (можно использовать разделяемую память, память со сборкой мусора, память из заранее выделенного пула и прочее).Стандартные контейнеры и алгоритмы получают память и обращаются к нейчерез средства, обеспечиваемые распределителем памяти.Стандартный распределитель памяти, задаваемый стандартным шаблоннымклассом allocator из заголовочного файла <memory>, выделяет память припомощи операции new и по умолчанию используется всеми стандартными контейнерами.template <class T> class allocator {public:typedef T* pointer;typedef T& reference;// . . .allocator() throw();// .
. .pointer allocate (size_type n); // выделение памяти для// n объектов типа Tvoid deallocate (pointer p, size_type n);// освобождает память для n объектов типа Т,//деструкторы не вызываютсяvoid construct (pointer p, const T& val);// инициализация памяти, на которую указывает р,// значением val};void destroy (pointer p);// вызывает деструктор для *p, не освобождая память// . . .16.3.ИтераторыКаждый контейнер содержит итераторы, поддерживающие стандартныйнабор итерационных операций со стандартными именами и смыслом.Итератор – это класс, объекты, которого по отношению к контейнерам играют роль указателей.
Итераторы поддерживают абстрактную модель совокупности данных как последовательности объектов (что и представляет собой любойконтейнер). Обычно, основное действие с последовательностью элементов – перебор. Он организуется с помощью итераторов. Итератор – это класс, чьи объектывыполняют ту же роль по отношению к контейнеру, которую выполняют указатели по отношению к массиву. Указатель может использоваться в качестве средства доступа к элементам массива, а итератор – в качестве средства доступа кэлементам контейнера. Но, понятия "нулевой итератор" не существует. При организации цикла для последовательного обращения к элементам контейнераокончание цикла фиксируется на основе применения специальной функции длясравнения с концом последовательности элементов контейнера.Классы итераторов и функции, предназначенные для работы с ними, находятся в библиотечном файле <iterator>.99Каждый контейнер содержит ряд ключевых методов, позволяющих найтиконцы последовательности элементов в виде соответствующих значений итераторов.
Это:iterator begin() – возвращает итератор, который указывает на первыйэлемент последовательности.const_iterator begin() constiterator end() – возвращает итератор, который указывает на элемент,следующий за последним элементом последовательности (используется при оформлении циклов).const_iterator end () constreverse_iterator rbegin() - возвращает итератор, указывающий напервый элемент в обратной последовательности (используетсядля работы с элементами последовательности в обратном порядке).const_reverse_iterator rbegin() constreverse_iterator rend() - возвращает итератор, указывающий наэлемент, следующий за последним в обратной последовательности.const_reverse_iterator rend () const«Прямые» итераторы:begin()AВСDCBAend()«Обратные» итераторы:rbegin()Drend()Пусть р – объект-итератор.
К каждому итератору можно применить, какминимум, три ключевые операции:• *р – элемент, на который указывает итератор («разыменование» итератора),• р++ - переход к следующему элементу последовательности,• == - операция сравнения.Пример:iterator p = v.begin()100Такое присваивание верно независимо от типа контейнера v . Теперь *p –содержимое первого элемента контейнера v.Замечание: при проходе последовательности как прямым, так и обратнымитератором переход к следующему элементу будет р++ (а не р-- !).Не все виды итераторов поддерживают один и тот же набор операций.В библиотеке STL введено 5 категорий итераторов:1.
Ввода (input)2. Вывода (output)3. Однонаправленный (forward)4. Двунаправленный (bidirectional), контейнеры list, map, set5. C произвольным доступом (random_access), контейнеры vector иdequeИтераторыЧтениеВыводаВводаОднонаправленныеДвунаправленныеПроизвольный доступДост Зауп письИзменениеСравнениеp++++pp++p->f++pp++p->f *p=e++pp++++pp->f *p=ep---pp++++pp-p->f*p=e--pp[n]p+n n+p p–np-q p+=n p-=n*p=ex=*px=*px=*px=*pp==qp!=qP==qp!=qP==qp!=qp==q p!=qp<q p>qp>=q p<=qКаждая последующая категория, начиная с третьей, является более мощной,чем предыдущие категории.ВводВыводОднонаправленныйДвунаправленныйС произвольнымдоступомПринято такое соглашение, что при описании алгоритмов, входящих в STLиспользуют стандартные имена формальных параметров.
В зависимости от названия итератора в профиле алгоритма, должен использоваться итератор уровня«не ниже чем». То есть по названию параметров шаблона можно понять, какогорода итератор требуется, а, следовательно, и к какому контейнеру применим алгоритм.101Пример: шаблонная функция find().Для этой функции нужны: итератор, указывающий на элемент контейнера, скоторого начинается поиск, итератор, содержащий элемент, на котором поискзаканчивается, и элемент, поиск значения которого осуществляется. Для целейфункции достаточно итератора ввода (из контейнера).template < class InputInterator, class T >InputIterator find (InputIterator first,InputIterator last,const T& value){while ( first != last && *first != value )first ++;return first;}16.4.АлгоритмыАлгоритмы STL (их около 60) реализуют некоторые распространенныеоперации с контейнерами, которые не реализуются методами каждого из контейнеров (например, просмотр, сортировка, поиск, удаление элементов и прочие).Такие операции являются универсальными для любого из контейнеров и поэтомунаходятся вне этих контейнеров.