Как сделать шаблонный класс с

Обновлено: 06.07.2024

Вот не совсем понимаю, как написать конструктор для массива, да еще и конструктор копирования
Может кто помочь?
Извените не там созадл тему, переместите для начинающих))

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

Шаблоны классов
Зачем нужен шаблонный класс, какой от него главный смысл?

VS 2013 - шаблоны классов -> обязательно ли функции шаблона класса делать встроенными?
Добрый день, столкнулась со следующей проблемой при работе с шаблонами классов: Имеется шаблон.

Для операции индексирования полезно реализовать две сигнатуры - T& operator [] (int) для записи, и T operator [] (int) const для чтения.

В общем, начал ты неплохо. Правь код, выкладывай исправленный вариант, и будем посмотреть дальше.

Использование шаблонов в C++

Программирование и разработка

Использование шаблонов в C++

Шаблон C ++ создает алгоритм, независимый от типа используемых данных. Таким образом, один и тот же алгоритм с множеством экземпляров одного и того же типа может использовать разные типы при разных исполнениях. Сущности переменной, функции, структуры и класса могут иметь шаблоны. В этой статье объясняется, как объявлять шаблоны, как определять шаблоны и как их применять в C ++. Вы должны уже знать вышеупомянутые сущности, чтобы понимать темы, затронутые в этой статье.

Скалярные типы: void, bool, char, int, float и pointer.

Классы как типы

Конкретный класс можно рассматривать как тип, а его объекты — как возможные значения.

Универсальный тип представляет собой набор скалярных типов. Список скалярных типов обширен. Тип int, например, имеет другие связанные типы, такие как short int, long int и т. Д. Универсальный тип также может представлять набор классов.

Переменная

Пример объявления и определения шаблона следующий:

Прежде чем продолжить, обратите внимание, что такого рода операторы не могут появляться в функции main () или в любой области блока. Первая строка — это объявление заголовка шаблона с выбранным программистом универсальным именем типа T. Следующая строка — это определение идентификатора pi, который относится к универсальному типу T. Точность того, является ли T. int, float или какой-либо другой тип может быть выполнен в функции C ++ main () (или какой-либо другой функции). Такая точность будет сделана с переменной pi, а не T.

Первая строка — это объявление заголовка шаблона. Это объявление начинается с зарезервированного слова, шаблона, а затем с открытой и закрытой угловых скобок. В угловых скобках указан как минимум один идентификатор универсального типа, например T, указанный выше. Может быть несколько идентификаторов универсального типа, каждому из которых предшествует зарезервированное слово typename. Такие универсальные типы в этой позиции называются параметрами шаблона.

Следующий оператор может быть записан в main () или в любой другой функции:

И функция отобразит 3.14. Выражение pi определяет точный тип T для переменной pi. Специализация определяет конкретный тип данных для параметра шаблона. Создание экземпляра — это внутренний процесс C ++ по созданию определенного типа, такого как float, в данном случае. Не путайте создание экземпляра параметра шаблона и создание экземпляра класса. В теме шаблона многие типы данных могут иметь одно общее имя типа, тогда как многие классы могут иметь одно общее имя класса. Однако общее имя класса для классов просто называется классом, а не именем класса. Кроме того, значение относится к типу данных, например int, так же как созданный объект относится к классу, например классу String.

При специализации выбранный тип данных, например float, помещается в угловые скобки после переменной. Если в объявлении заголовка шаблона содержится более одного параметра шаблона, в выражении специализации будет соответствующее количество типов данных в том же порядке.

В специализации тип известен как аргумент шаблона. Не путайте это с аргументом функции для вызова функции.

Тип по умолчанию

Если при специализации тип не указан, предполагается тип по умолчанию. Итак, из следующего выражения:

Примечание: тип по умолчанию все еще можно изменить при специализации, установив другой тип.

Структура

В следующем примере показано, как параметр шаблона можно использовать со структурой:

template typename T > struct Ages
<
T John = 11 ;
T Peter = 12 ;
T Mary = 13 ;
T Joy = 14 ;
> ;

Это возраст учащихся класса (класса). Первая строка — это объявление шаблона. Тело в фигурных скобках — это фактическое определение шаблона. Возраст можно вывести в функции main () следующим образом:

Ages int > grade7 ;
cout grade7. John ‘ ‘ grade7. Mary ‘ \n ‘ ;

Результат: 11 13. Первый оператор здесь выполняет специализацию. Обратите внимание, как это было сделано. Он также дает имя для объекта структуры: grade7. Второй оператор имеет обычные выражения объекта структуры. Структура похожа на класс. Здесь Ages похож на имя класса, а grade7 — это объект класса (структура).

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

template typename T , typename U > struct Ages
<
T John = 11 ;
U Peter = 12.3 ;
T Mary = 13 ;
U Joy = 14.6 ;
> ;

Соответствующий код для функции main () выглядит следующим образом:

Ages int , float > grade7 ;
cout grade7. John ‘ ‘ grade7. Peter ‘ \n ‘ ;

Результат: 11 12.3. При специализации порядок типов (аргументов) должен соответствовать порядку универсальных типов в объявлении.

Объявление шаблона можно отделить от определения следующим образом:

template typename T , typename U > struct Ages
<
T John ;
U Peter ;
T Mary ;
U Joy ;
> ;

Ages int , float > grade7 = < 11 , 12.3 , 13 , 14.6 >;

Первый сегмент кода — это просто объявление шаблона (нет присваиваний). Второй сегмент кода, который является просто оператором, является определением идентификатора grade7. Слева — объявление идентификатора grade7. Справа находится список инициализаторов, который присваивает соответствующие значения элементам структуры. Второй сегмент (оператор) можно записать в функцию main (), в то время как первый сегмент остается вне функции main ().

Не тип

Примеры типов, не относящихся к данным, включают int, указатель на объект, указатель на функцию и типы auto. Есть и другие нетипы, которые в этой статье не рассматриваются. Нетип подобен неполному типу, значение которого задается позже и не может быть изменено. В качестве параметра он начинается с определенного не типа, за которым следует идентификатор. Значение идентификатора дается позже, при специализации, и не может быть изменено снова (как константа, значение которой задается позже). Следующая программа иллюстрирует это:

При специализации первый тип, int, в угловых скобках используется скорее для формальности, чтобы убедиться, что количество и порядок параметров соответствуют количеству и порядку типов (аргументов). Значение N дано при специализации. Результат: 11 14.6.

Частичная специализация

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

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

Соответствующий код в функции main () может быть следующим:

Ages int , float > grade7 ;
cout grade7. John ‘ ‘ grade7. Joy ‘ \n ‘ ;

Результат: 11 14.6.

Пакет параметров шаблона

Пакет параметров — это параметр шаблона, который принимает ноль или более универсальных типов шаблона для соответствующих типов данных. Параметр пакета параметров начинается с зарезервированного слова typename или class. Далее следуют три точки, а затем идентификатор упаковки. Следующая программа показывает, как пакет параметров шаблона может использоваться со структурой:

11 13
12,3 14,6
11 14,6
11 14,6

Шаблоны функций

Упомянутые выше возможности шаблона применяются аналогично шаблонам функций. В следующей программе показана функция с двумя общими параметрами шаблона и тремя аргументами:

Результат выглядит следующим образом:

В магазине 12 книг стоимостью 500 долларов.

Отделение от прототипа

Определение функции можно отделить от ее прототипа, как показано в следующей программе:

Примечание. Объявление шаблона функции не может появляться в функции main () или в любой другой функции.

Перегрузка

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

В магазине 12 книг стоимостью 500 долларов.

В магазине 12 книг стоимостью 500 долларов.

Шаблоны классов

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

Результат выглядит следующим образом:

В магазине 12 книг стоимостью 500 долларов.

Следующая программа представляет собой указанную выше программу с объявлением заголовка шаблона:

Вместо слова typename в списке параметров шаблона можно использовать слово class. Обратите внимание на специализацию в объявлении объекта. Результат все тот же:

В магазине 12 книг стоимостью 500 долларов.

Разделительная декларация

Объявление шаблона класса можно отделить от кода класса следующим образом:

Работа со статическими членами

В следующей программе показано, как получить доступ к статическому члену данных и статической функции-члену:

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

Официальная статическая функция-член.

Компиляция

Объявление (заголовок) и определение шаблона должны быть в одном файле. То есть они должны быть в одной единице перевода.

Заключение

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

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

Классы-шаблоны полезны тогда, когда класс содержит логику, допускающую значительные обобщения. Например, алгоритм для обработки очереди целых чисел также будет работать с очередью символов. Аналогично механизм, поддерживающий связанный список почтовых адре­сов, также может поддерживать связанный список сведений об автомобилях. Используя классы- шаблоны, можно создавать классы, поддерживающие очереди, связанные списки и т. д. для про­извольных типов данных. Компилятор автоматически создаст корректный код, основываясь на типе данных, указанном перед компиляцией. Общая форма объявления класса-шаблона показа­на ниже:

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

После создания класса-шаблона можно создать конкретный экземпляр этого класса, используя следующую общую форму:

Здесь тип является именем типа данных, с которыми будет оперировать данный класс.

Функции-члены класса-шаблона являются сами по себе автоматически шаблонами. Нет необхо­димости особым образом указывать на то, что они являются шаблонами с использованием ключе­вого слова template.

Обратим внимание, каким образом нужный тип данных подставляется в угловые скобки. Изме­няя тип данных, указываемый при создании объектов класса stack, одновременно изменяется тип данных, хранящихся в стеке. Например, можно создать другой стек, хранящий указатели на символы:

Также можно создать стек, содержащий определенный тип данных. Например, можно хра­нить адреса, используя структуру:

struct addr char name[40];
char street[40];
char city[30];
char state[3];
char zip[12];
>

Далее можно использовать класс stack для создания стека, в котором хранятся объекты типа addr:

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

Шаблоны обеспечивают непосредственную поддержку обобщенного программирования (т.е. c использованием типов в качестве параметров)

Шаблон зависит только от тех свойств параметра-типа, которые он явно использует

Существуют шаблоны функций и классов

Инстанцирование

Процесс порождения функции или класса из шаблона называется инстанцированием

Процесс генерации объявления класса по шаблону класса и аргументу шаблона

Версия шаблона для конкретного аргумента шаблона называется специализацией

Генерация версий шаблона - задача компилятора

1.1 Шаблоны функций

Для создания шаблона используется ключевое слово template. Также указывается пока неопределенный тип T.

Рассмотрим пример шаблонной функции swap для обмена значений двух переменных

Для получения функции проведем инстанцирование

Еще один пример: функция сортировки

Пример шаблона с целочисленным параметром

Примеры использования шаблонов

1.2 Шаблоны классов

Аналогично функциям можно создавать шаблоны классов. Рассмотрим пример стека:

Воспользоваться шаблоном класса можно так

Описание конструктора и деструктора шаблонного класса

Описание методов push и pop

Описание методов определения размера стека

Примеры инстанцирования

Рассмотрим примеры использования шаблона стека

1.3 Параметры шаблонов

Параметры шаблона

У шаблонов могут быть параметры различных типов

Инстанцирование выполняется с указанием значения параметра

В шаблонах допускается использование различных видов параметров

Если в шаблоне класса или функции необходимо использовать один и тот же шаблон, но с разными параметрами, то используются параметры-шаблоны. Например:

Перегрузка шаблонов

Специализация шаблонов

Явное инстанцирование

Явное инстанцирование используется

  1. Если инстанцирование шаблонов отнимает слишком много времени
  2. Если порядок компиляции должен быть абсолютно предсказуем

2 Специализация шаблонов

Для чего нужна специализация шаблонов? Для того чтобы задать шаблон для отдельного значения параметра (типа или значения).

В приведённом примере создаётся шаблон функции сравнения двух элементов одного типа. Так можно сравнивать любые числа, но не строки.

Для строк создаётся специализация.

2.1 Класс Bag

Шаблон класса Bag

В следующем примере приводится шаблон класса Bag, который является

динамическим контейнером элементов и его специализация,

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

2.2 Пример с наследованием

Мы можем использовать специализацию при наследовании.

Рассмотрим следующую ситуацию. Допустим мы хотим создать класс, услуги которого базируются на сходных по назначению, но отличных в их реализации классах BaseA и BaseB. Если оба базовых класса обладают схожим интерфейсом, то логично оформить наш класс в виде шаблона:

если разработчику необходима информация о базовых классах объектов, основанных на шаблоне Derived. Как ее получить?

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

Описываем шаблон класса-наследника, в который помещается метод GetBaseClass

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

Создание шаблонов классов

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

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

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

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

Метод find выполняет поиск узла с заданным ключом и возвращает указатель на него в случае успешного поиска и 0 в случае отсутствия такого узла в списке:

Метод insert вставляет в список узел после узла с ключом key и возвращает указатель на вставленный узел. Если такого узла в списке нет, вставка не выполняется и возвращается значение 0:

Метод remove удаляет узел с заданным ключом из списка и возвращает значение true в случае успешного удаления и false , если узел с таким ключом в списке не найден:

Методы печати списка в прямом и обратном направлении поэлементно просматривают список, переходя по соответствующим ссылкам:

Деструктор списка освобождает память из-под всех его элементов:

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

Класс List предназначен для хранения целых чисел. Чтобы хранить в нем данные любого типа, требуется описать этот класс как шаблон и передать тип в качестве параметра.

Синтаксис описания шаблона:

Шаблон класса начинается с ключевого слова template . В угловых скобках записывают параметры шаблона. При использовании шаблона на место этих параметров шаблону передаются аргументы: типы и константы, перечисленные через запятую.

Типы могут быть как стандартными, так и определенными пользователем. Для их описания в списке параметров используется ключевое слово class . В простейшем случае одного параметра это выглядит как . Здесь T является параметром-типом. Имя параметра может быть любым, но принято начинать его с префикса T . Внутри класса-шаблона параметр может появляться в тех местах, где разрешается указывать конкретный тип, например:

Класс TData можно рассматривать как параметр, на место которого при компиляции будет подставлен конкретный тип данных. Получившийся шаблонный класс имеет тип List.

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

возвр_тип имя_класса :: имя_функции (список_параметров функции)

Проще рассмотреть синтаксис описания методов шаблона на примере:

  • Описание параметров шаблона в заголовке функции должно соответствовать шаблону класса.
  • Локальные классы не могут иметь шаблоны в качестве своих элементов.
  • Шаблоны методов не могут быть виртуальными.
  • Шаблоны классов могут содержать статические элементы , дружественные функции и классы.
  • Шаблоны могут быть производными как от шаблонов, так и от обычных классов, а также являться базовыми и для шаблонов, и для обычных классов.
  • Внутри шаблона нельзя определять friend -шаблоны.

Если у шаблона несколько параметров, они перечисляются через запятую. Ключевое слово class требуется записывать перед каждым параметром, например:

Параметрам шаблонного класса можно присваивать значения по умолчанию, они записываются после знака " http://www.intuit.ru/2010/edi" >

Ниже приведено полное описание параметризованного класса двусвязного списка List .

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

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

  • переменная целого, символьного, булевского или перечислимого типа ;
  • указатель на объект или указатель на функцию;
  • ссылка на объект или ссылка на функцию;
  • указатель на элемент класса.

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

В качестве примера создадим шаблон класса, содержащего блок памяти определенной длины и типа:

У класса-шаблона могут быть друзья, и шаблоны тоже могут быть друзьями. Класс может быть объявлен внутри шаблона, а шаблон - внутри как класса, так и шаблона. Единственным ограничением является то, что шаблонный класс нельзя объявлять внутри функции. В любом классе, как в обычном, так и в шаблоне, можно объявить метод-шаблон. После создания и отладки шаблоны классов удобно помещать в заголовочные файлы .

Читайте также: