C++. Сборник рецептов - [121]

Шрифт
Интервал

> om.gimmeAnObject(p1); // Однако не здесь, так как компилятор может

> om.gimmeAnObject(p2); // догадаться о типе T по аргументам

>}

Обсуждение

При обсуждении шаблонов функций или классов слова «параметр» и «аргумент» становятся несколько двусмысленными. Имеется по два вида каждого: шаблона и функции. Параметры шаблона — это параметры в угловых скобках, например >T в примере 8.13, а параметры функции — это параметры в обычном смысле.

Рассмотрим класс >ObjectManager из примера 8.13. Это упрощенная версия шаблона фабрики, описанного в рецепте 8.2, так что мне потребовалось объявить метод >gimmeAnObject, который создает новые объекты и который клиентский код сможет использовать вместо непосредственного обращения к >new. Это можно сделать, либо возвращая указатель на новый объект, либо изменяя указатель, переданный в метод клиентским кодом. Давайте посмотрим на каждый из этих подходов.

Объявление шаблона метода требует, чтобы было использовано ключевое слово >template и были указаны параметры шаблона.

>template T* gimmeAnObject();

>template void gimmeAnObject(T*& p);

Оба этих метода используют в качестве параметра шаблона >T, но они не обязаны это делать. Каждый из них представляет параметр шаблона только для данного метода, так что их имена не связаны друг с другом. То же самое требуется сделать для определения этих шаблонов методов, т.е. использовать это же ключевое слово и перечень параметров шаблона. Вот как выглядят мои определения.

>template

>T* ObjectManager.:gimmeAnObject() {

> return(new T);

>}


>template

>void ObjectManager::gimmeAnObject(T*& p) {

> p = new T;

>}

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

>X* p1 = om.gimmeAnObject();

>X — это имя некоего класса. Либо можно позволить компилятору догадаться об аргументах параметров шаблона, передав в методы аргументы типа (типов) параметров шаблона. Например, можно вызвать вторую форму >gimmeAnObject, не передавая ей ничего в угловых скобках.

>om.gimmeAnObject(p1);

Это работает благодаря тому, что компилятор может догадаться о >T, посмотрев на >p1 и распознав, что он имеет тип >X*. Такое поведение работает только для шаблонов функций (методов или отдельных) и только тогда, когда параметры шаблона понятны из аргументов функции.

Шаблоны методов не имеют большой популярности при разработке на C++, но время от времени они оказываются очень полезны, так что следует знать, как создавать их. Я часто сталкиваюсь с необходимостью сдерживать себя, когда мне хочется использовать метод, который бы работал с типами, которые не связаны друг с другом механизмом наследования. Например, если есть метод >foo, который должен принимать один аргумент, который всегда будет классом, наследуемым от некоторого базового класса, то шаблон не требуется: здесь можно просто сделать параметр типа базового класса или ссылки. После этого этот метод будет прекрасно работать с параметром, имеющим тип любого подкласса; это обеспечивается самим C++.

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

Смотри также

Рецепт 8.11.

8.13. Перегрузка операторов инкремента и декремента

Проблема

Имеется класс, для которого имеют смысл операции инкремента и декремента, и требуется перегрузить >operator++ и >operator--, которые позволят легко и интуитивно выполнять инкремент и декремент объектов этого класса.

Решение

Чтобы это сделать, перегрузите префиксную и постфиксную формы >++ и >--. Пример 8.14 показывает обычную методику перегрузки операторов инкремента и декремента.

Пример 8.14. Перегрузка инкремента и декремента

>#include


>using namespace std;


>class Score {

>public:

> Score() : score_(0) {}

> Score(int i) : score_(i) {}

> Score& operator++() {

>  // префикс

>  ++score_;

>  return(*this);

> }

> const Score operator++(int) {

>  // постфикс

>  Score tmp(*this);

>  ++(*this); // Использование префиксного оператора

>  return(tmp);

> }

> Score& operator--() {

>  --score_;

>  return(*this);

> }

> const Score operator--(int x) {

>  Score tmp(*this);

>  --(*this);

>  return(tmp);

> }

> int getScore() const {return(score_);}

>private:

> int score_;

>};


>int main() {

> Score player1(50);

> player1++;

> ++player1; // score = 52

> cout << "Счет = " << player1.getScore() << '\n';

> (--player1)--; // score_ = 50

> cout << "Счет = " << player1.getScore() << '\n';

>}

Обсуждение

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


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Создаем порт для FreeBSD своими руками. Часть II

Система сборки программ, используемая во FreeBSD, имеет значительно большие возможности, чем те, которые мы задействовали. Какие это возможности и как их использовать в своих портах?


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.