И.А. Волкова, А.В. Иванов, Л.Е. Карпов - Основы объектно-ориентированного программирования. Язык программирования С++ (1114893), страница 16
Текст из файла (страница 16)
Так же, как и при поиске оптимально отождествляемой функции дляобычных функций, если полученное множество подходящих вариантов состоит из одной функции, то вызов разрешим. Если множество пусто или содержит более одной функции, то генерируетсясообщение об ошибке.15.5. Шаблонные классыТак же, как и для функций, можно описать шаблоны для классов. Механизмшаблонов при описании класса позволяет, например, обобщенно описыватьмножество классов, единственное отличие которых заключаетсяв используемых типах данных.Объявление шаблона класса:Процесс генерации объявления класса по шаблону класса и фактическим аргументам шаблона называется инстанцированием шаблона.Обычно он совмещается с объявлением объекта соответствующего конкретного типа.
Синтаксис такого объявления:108Параметрический полиморфизмИмякласса<Списокпараметровшаблона>Идентификаторобъекта;Функции-члены класса-шаблона автоматически становятся функциями-шаблонами. Для них не обязательно явно задавать ключевое слово template.Пример:Описание стека для хранения величин разных типов данных:template <class T> class stack{T* body;int size;int top;public:stack ( int sz = 10 ){size = sz;top = 0;body = new T[size];}~stack() { delete[] body; }T pop(){--top;return body[top];}void push ( T x ){body[top] = x;top++;}};int main(){stack<int>S1( 20);stack<char>S2(256);stack<double> S3( 16);// .
. .}Так же, как и в шаблонах функций, использование шаблонов классовсокращает текст алгоритма, но не сокращает размер кода программы. Реальногенерируется столько описаний классов, сколько было объявлений объектовс разными параметрами шаблонов.Шаблонные классы могут иметь дружественные функции и классы.Дружественная функция, которая не использует параметры шаблона, имеетсяв единственном экземпляре, то есть она является дружественной для всехинстанцирований класса.Дружественная функция, которая использует параметры шаблона, самаявляется шаблоном.
Конкретная реализация такой функции с учётом специфицированных параметров (порожденная функция) является дружественной для такого инстанцирования класса, которое совпадает по типамс фактическими типами аргументов порожденной функции.109Параметрический полиморфизмПример:template <class T> class Y{ . . .};template <class T> class X{// . . .public:/* функция f1() является дружественной ко всеминстанцированиям класса */friend void f1();/* порождение функции f2() для фактического типа T являетсядружественной только к тому инстанцированию класса X,которое подходит по фактическому типу–параметру. */friend Y<T> f2(Y<T> par1);// .
. .};template <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).110Параметрический полиморфизмПример:typedef unsigned int uint;template <class T, int s> class vect{ /* .
. . */ };int main(){vect <uint,16> v1;vect <unsigned int,16> v2;. . .}Объекты v1 и v2 имеют один и тот же тип.Кроме того, эквивалентность типов определяется с точностью до вычисления константных выражений на этапе компиляции. Поэтому объекты v1и v3vect <uint,16> v1;vect <unsigned int,10+6> v3;имеют одинаковый тип.111Стандартная Библиотека шаблонов STLГлава 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 ›— ассоциативный массив112Стандартная Библиотека шаблонов STL—Multimap ‹ key, val › — ассоциативный массив для хранения пар«ключ–значение», где с каждым ключом может быть связано болееодного значения.ПримечаниеСтрого говоря, стек, очередь, очередь с приоритетами не считаются стандартными контейнерами.
Они построены с ограничениями функциональностина базе других контейнеров. Тем не менее, они включены в библиотеку STLнаряду с другими стандартными контейнерами.В каждом классе-контейнере определен набор функций для работыс этим контейнером, причем все контейнеры поддерживают стандартныйнабор базовых операций (функции, одинаково называющиеся, имеющиеодинаковый профиль и семантику, их примерно 15–20).
Например, функцияpush_back() помещает элемент в конец контейнера, функция size() выдаеттекущий размер контейнера. Основные операции включаются в следующиегруппы:— доступ к элементу,— вставка элемента,— удаление элемента,— итераторы.Операции, которые не могут быть эффективно реализованы для всехконтейнеров, не включаются в набор общих операций. Например, обращениепо индексу введено для контейнера vector, но не для list.Каждый контейнер в своей открытой области содержит набор определений стандартных имен типов.
Среди них есть следующие имена:— value_type — тип элемента,— allocator_type — тип распределителя памяти,— size_type — тип, используемый для индексации,— iterator, const_iterator — итератор,— reverse_iterator, const_reverse_iterator — обратный итератор,— pointer, const_pointer — указатель на элемент,— reference, const_reference — ссылка на элемент.Эти имена определяются внутри каждого контейнера так, как это необходимо для соответствующего контейнера. При этом реальные типы инкапсулированы. Это позволяет писать программы с использованием контейнеров, не зависящие от типов данных, реально используемыхв контейнерах.16.2. Распределители памятиКаждый контейнер имеет аргумент, называемый распределителем памяти(allocator), который используется при выделении памяти под элементы контейнера и предназначен для того, чтобы освободить разработчиков контейнеров, а также алгоритмов, от подробностей физической организации памяти.Распределитель памяти обеспечивает стандартные способы выделенияи перераспределения памяти, а также стандартные имена типов для указате113Стандартная Библиотека шаблонов STLлей и ссылок.
Стандартная библиотека обеспечивает стандартный распределитель памяти. Кроме того, можно задать свои распределители памяти,предоставляющие альтернативный доступ к памяти (можно использоватьразделяемую память, память со сборкой мусора, память из заранее выделенного пула и прочее).Стандартные контейнеры и алгоритмы получают память и обращаютсяк ней через средства, обеспечиваемые распределителем памяти.Стандартный распределитель памяти, задаваемый стандартным шаблонным классом 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);// вызывает деструктор для *р, не освобождая память,// на которую указывает р// .
. .16.3. ИтераторыКаждый контейнер содержит итераторы, поддерживающие стандартный набор итерационных операций со стандартными именами и смыслом.Итератор — это класс, объекты, которого по отношению к контейнерам играют роль указателей. Итераторы поддерживают абстрактную модельсовокупности данных как последовательности объектов (что и представляетсобой любой контейнер).
Обычно, основное действие с последовательностьюэлементов — перебор. Он организуется с помощью итераторов. Итератор —это класс, чьи объекты выполняют ту же роль по отношению к контейнеру,которую выполняют указатели по отношению к массиву. Указатель можетиспользоваться в качестве средства доступа к элементам массива, а итератор — в качестве средства доступа к элементам контейнера. Но, понятия«нулевой итератор» не существует.