При обсуждении шаблонов функций или классов слова «параметр» и «аргумент» становятся несколько двусмысленными. Имеется по два вида каждого: шаблона и функции. Параметры шаблона — это параметры в угловых скобках, например T
Рассмотрим класс ObjectManager
gimmeAnObject
, который создает новые объекты и который клиентский код сможет использовать вместо непосредственного обращения к new
. Это можно сделать, либо возвращая указатель на новый объект, либо изменяя указатель, переданный в метод клиентским кодом. Давайте посмотрим на каждый из этих подходов.Объявление шаблона метода требует, чтобы было использовано ключевое слово template
template
template
Оба этих метода используют в качестве параметра шаблона 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
Но может потребоваться функция, которая работает с параметрами, которые не наследуются от одного и того же базового класса (или классов). В этом случае можно либо написать несколько раз один и тот же метод — по одному разу для каждого из типов, либо сделать его шаблоном метода. Использование шаблонов также позволяет использовать специализацию, предоставляющую возможность создавать реализации шаблонов для определенных аргументов шаблона. Но это выходит за рамки одного рецепта, так что сейчас я прекращаю обсуждение, но это мощная методика, поэтому при использовании программирования шаблонов не забудьте про такую возможность.
Рецепт 8.11.
8.13. Перегрузка операторов инкремента и декремента
Имеется класс, для которого имеют смысл операции инкремента и декремента, и требуется перегрузить operator++
operator--
, которые позволят легко и интуитивно выполнять инкремент и декремент объектов этого класса.Чтобы это сделать, перегрузите префиксную и постфиксную формы ++
--
. Пример 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);
}