- Любовные романы
- Фантастика и фэнтези
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
C++. Сборник рецептов - Д. Стефенс
Шрифт:
Интервал:
Закладка:
template<typename T, typename N = short>
Как и в случае с параметрами функций по умолчанию, их можно использовать только для отдельных параметров при условии, что этот последний параметр или все параметры справа от него имеют аргументы по умолчанию.
В примере 8.12 определение шаблона дается в том же месте, что и его объявление. Обычно это делается для экономии места, занимаемого примером, не в данном случае есть и еще одна причина. Шаблоны (классов или функций — см. рецепт 8.12) компилируются в двоичную форму только тогда, когда создается их экземпляр. Таким образом, невозможно создать объявление шаблона в заголовочном файле, а его реализацию — в исходном файле (т.е. .cpp) Причина заключается в том, что в нем нечего компилировать! Из этого правила имеются исключения, но обычно при написании шаблона класса его реализация должна помешаться в заголовочном файле или встраиваемом файле, который подключается заголовочным.
В этом случае требуется использовать несколько необычный синтаксис. Методы и другие части класса объявляются как в обычном классе, но при определении методов требуется включить дополнительные лексемы, которые говорят компилятору, что это части шаблона класса. Например, getVal можно определить вот так (сравните с примером 8.12)
template<typename T>
const T& TreeNode<T>::getVal() const {
return(val_);
}
Тело функции выглядит точно так же.
Однако с шаблонами следует быть осторожными, так как если написать шаблон, который используется повсеместно, то можно получить раздувание кода, что случается, когда один и тот же шаблон с одними и теми же параметрами (например, TreeNode<int, short>) компилируется в нескольких объектных файлах. По существу в нескольких файлах окажется одно и то же двоичное представление экземпляра шаблона, и это сделает библиотеку или исполняемый файл значительно больше по размеру, чем требуется.
Одним из способов избежать этого является использование явного создания экземпляров, что позволяет указать компилятору создать версию шаблона класса для определенного набора аргументов шаблона. Если сделать это в таком месте, которое компонуется вместе с остальными клиентскими частями, то раздувания кода не произойдет. Например, если известно, что в приложении будет использоваться TreeNode<string>, то в общий исходный файл можно поместить такую строку.
// common.cpp
template class TreeNode<string>;
Соберите динамическую библиотеку с этим файлом, и после этого код, использующий TreeNode<string>, сможет применять эту библиотеку динамически, не содержа своей собственной скомпилированной версии шаблона. Другой код может включить заголовочный файл шаблона класса, затем скомпоноваться с этой библиотекой и. следовательно, избежать необходимости иметь свою копию. Однако этот подход требует проведения экспериментов, так как не все компиляторы имеют одинаковые проблемы с раздуванием кода, но это общий подход для его минимизации.
Шаблоны C++ (как классов, так и функций) — это очень обширная тема, и имеется огромное количество методик создания мощных, эффективных проектов на основе шаблонов. Великолепным примером шаблонов классов являются контейнеры из стандартной библиотеки, такие как vector, list, set и другие, которые описываются в главе 15. Большая часть интересных разработок, описанных в литературе по С++, связана с шаблонами. Если вы заинтересовались этим предметом, почитайте группы новостей comp.lang.std.c++ и comp.lang.c++. В них всегда можно найти интересные вопросы и ответы на них.
Смотри такжеРецепт 8.12.
8.12. Написание шаблона метода класса
ПроблемаИмеется один метод, который должен принимать параметр любого типа, и невозможно ограничиться каким-либо одним типом или категорией типов (используя указатель на базовый класс).
РешениеИспользуйте шаблон метода и объявите параметр шаблона для типа объекта. Небольшая иллюстрация приведена в примере 8.13.
Пример 8.13. Использование шаблона метода
class ObjectManager {
public:
template<typename T> T* gimmeAnObject();
template<typename T>
void gimmeAnObject(T*& p);
};
template<typename T>
T* ObjectManager::gimmeAnObject() {
return(new T);
}
template<typename T>
void ObjectManager::gimmeAnObject(T*& p) {
p = new T;
}
class X { /*...*/ };
class Y { /* ... */ };
int main() {
ObjectManager om;
X* p1 = om.gimmeAnObject<X>(); // Требуется указать параметр
Y* p2 = om.gimmeAnObject<Y>(); // шаблона
om.gimmeAnObject(p1); // Однако не здесь, так как компилятор может
om.gimmeAnObject(p2); // догадаться о типе T по аргументам
}
ОбсуждениеПри обсуждении шаблонов функций или классов слова «параметр» и «аргумент» становятся несколько двусмысленными. Имеется по два вида каждого: шаблона и функции. Параметры шаблона — это параметры в угловых скобках, например T в примере 8.13, а параметры функции — это параметры в обычном смысле.
Рассмотрим класс ObjectManager из примера 8.13. Это упрощенная версия шаблона фабрики, описанного в рецепте 8.2, так что мне потребовалось объявить метод gimmeAnObject, который создает новые объекты и который клиентский код сможет использовать вместо непосредственного обращения к new. Это можно сделать, либо возвращая указатель на новый объект, либо изменяя указатель, переданный в метод клиентским кодом. Давайте посмотрим на каждый из этих подходов.
Объявление шаблона метода требует, чтобы было использовано ключевое слово template и были указаны параметры шаблона.
template<typename T> T* gimmeAnObject();
template<typename T> void gimmeAnObject(T*& p);
Оба этих метода используют в качестве параметра шаблона T, но они не обязаны это делать. Каждый из них представляет параметр шаблона только для данного метода, так что их имена не связаны друг с другом. То же самое требуется сделать для определения этих шаблонов методов, т.е. использовать это же ключевое слово и перечень параметров шаблона. Вот как выглядят мои определения.
template<typename T>
T* ObjectManager.:gimmeAnObject() {
return(new T);
}
template<typename T>
void ObjectManager::gimmeAnObject(T*& p) {
p = new T;
}
Теперь есть пара способов вызвать эти шаблоны методов. Во-первых, их можно вызвать явно, используя параметры шаблона, как здесь.
X* p1 = om.gimmeAnObject<X>();
X — это имя некоего класса. Либо можно позволить компилятору догадаться об аргументах параметров шаблона, передав в методы аргументы типа (типов) параметров шаблона. Например, можно вызвать вторую форму gimmeAnObject, не передавая ей ничего в угловых скобках.
om.gimmeAnObject(p1);
Это работает благодаря тому, что компилятор может догадаться о T, посмотрев на p1 и распознав, что он имеет тип X*. Такое поведение работает только для шаблонов функций (методов или отдельных) и только тогда, когда параметры шаблона понятны из аргументов функции.
Шаблоны методов не имеют большой популярности при разработке на C++, но время от времени они оказываются очень полезны, так что следует знать, как создавать их. Я часто сталкиваюсь с необходимостью сдерживать себя, когда мне хочется использовать метод, который бы работал с типами, которые не связаны друг с другом механизмом наследования. Например, если есть метод foo, который должен принимать один аргумент, который всегда будет классом, наследуемым от некоторого базового класса, то шаблон не требуется: здесь можно просто сделать параметр типа базового класса или ссылки. После этого этот метод будет прекрасно работать с параметром, имеющим тип любого подкласса; это обеспечивается самим C++.
Но может потребоваться функция, которая работает с параметрами, которые не наследуются от одного и того же базового класса (или классов). В этом случае можно либо написать несколько раз один и тот же метод — по одному разу для каждого из типов, либо сделать его шаблоном метода. Использование шаблонов также позволяет использовать специализацию, предоставляющую возможность создавать реализации шаблонов для определенных аргументов шаблона. Но это выходит за рамки одного рецепта, так что сейчас я прекращаю обсуждение, но это мощная методика, поэтому при использовании программирования шаблонов не забудьте про такую возможность.
Смотри такжеРецепт 8.11.
8.13. Перегрузка операторов инкремента и декремента
ПроблемаИмеется класс, для которого имеют смысл операции инкремента и декремента, и требуется перегрузить operator++ и operator--, которые позволят легко и интуитивно выполнять инкремент и декремент объектов этого класса.