本系列是对 C++ Templates The Complete Guide Second Edition 的学习和解读。本文介绍类模板。
和函数模板类似,类也可以实现部分类型的参数化。C++ 标准库的容器类就是类模板很好的例子。
类模板的实现
本文以数据结构中的栈(Stack)为例介绍类模板。
#include <vector>
#include <cassert>
template<typename T>
class Stack {
private:
std::vector<T> elems;
public:
void push(T const& elem);
void pop();
T const& top() const;
bool empty() const {
return elems.empty();
}
};
template<typename T>
void Stack<T>::push (T const& elem)
{
elems.push_back(elem);
}
template<typename T>
void Stack<T>::pop ()
{
assert(!elems.empty());
elems.pop_back();
}
template<typename T>
T const& Stack<T>::top () const
{
assert(!elems.empty());
return elems.back();
}
本例中,Stack 的类模板实现借助了标准库的 vector<>,节省了内存管理、构造函数、析构函数等的实现,可以聚焦于类模板的语法。
类模板的申明和函数模板的申明类似。
template<typename T>
class Stack {
...
};
也可以使用关键字 class 代替 typename,但是为了避免混淆,建议优先使用 typename。
template<class T>
class Stack {
...
};
在模板类内部,模板参数 T 可以像普通类型那样用于申明成员变量和成员函数。Stack 类的类型是 Stack<T>,因此,除了模板参数可以被推导的场景外,任何使用该类的类型的地方都必须使用 Stack<T>。但是,在类模板内部,可以省去类名后的模板参数。例如,你需要申明自己的拷贝构造函数和赋值操作:
emplate<typename T>
class Stack {
...
Stack (Stack const&); // copy constructor
Stack& operator= (Stack const&); // assignment operator
...
};
但是,在类模板外,则必须用完整的类型 Stack<T>:
template<typename T>
bool operator== (Stack<T> const& lhs, Stack<T> const& rhs);
在类外定义成员函数时,必须要使用 template<Typename T> 指明这是一个模板。例如:
template<typename T>
void Stack<T>::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem
}
类模板的使用
在 C++17 之前,使用类模板对象的时候,必须显示指定模板参数。
int main()
{
Stack<int> intStack; // stack of ints
Stack<std::string> stringStack; // stack of strings
// manipulate int stack
intStack.push(7);
std::cout << intStack.top() << ’\n’;
// manipulate string stack
stringStack.push("hello");
std::cout << stringStack.top() << ’\n’;
stringStack.pop();
}
类的模板参数可以是任何类型。例如:
Stack<float*> floatPtrStack; // stack of float pointers
Stack<Stack<int>> intStackStack; // stack of stack of ints
但是,需要注意的是: 在 C++11 之前,两个右尖括号之间必须留有空白:
Stack<Stack<int> > intStackStack; // OK with all C++ versions
Stack<Stack<int>> intStackStack; // ERROR before C++11
类模板的成员函数只有在被调用的时候才实例化。 这可以节省时间和空间,也使得允许模板类的部分使用(partial usage)。
类模板的部分使用
前面也提到过,类模板的成员变量只在需要的时候(被调用)才会实例化,也即支持类模板的部分使用。例如:
template<typename T>
class Stack {
...
void printOn() (std::ostream& strm) const

953

被折叠的 条评论
为什么被折叠?



