一、类模板
和函数模板一样,类模板也得通过template关键字来声明和定义,C++标准库中有很多容器都是类模板
示例
template <typename T>
class mystack
{
public:
mystack();
mystack(const mystack<T> &rval);
mystack<T> &operator=(const mystack<T> &rval);
~mystack();
void push(const T&ele);
void pop();
T top() const;
bool empty() const {
return elem.empty();
}
private:
vector<T> elem;
};
template <typename T>
mystack<T>::mystack()
{
cout<<__func__<<endl;
}
template <class T>
mystack<T>::mystack(const mystack<T> &rval):elem(rval.elem)
{
cout<<__func__<<endl;
}
template <class T>
mystack<T> & mystack<T>::operator=(const mystack<T> &rval)
{
cout<<__func__<<endl;
if (this==&rval) {
return *this;
}
this->elem=rval.elem;
return *this;
}
template <typename T>
mystack<T>::~mystack()
{
cout<<__func__<<endl;
}
template <typename T>
void mystack<T>::push(const T &elem)
{
cout<<__func__<<endl;
elem.push_back(elem);
}
template <typename T>
void mystack<T>::pop()
{
cout<<__func__<<endl;
try {
elem.pos_back();
}
catch (out_of_range){
cout<<"out_of_range"<<endl;
}
}
template <typename T>
T mystack<T>::top() const
{
cout<<__func__<<endl;
try {
return elem.back();
}
catch (out_of_range){
cout<<"out_of_range"<<endl;
}
}
上述代码通过vector定义了一个mystack模板类。模板类的定义依然得通过template和typename关键字
template <typename T>
class mystack
{
//......
};
此处的typename可以用class替换
类模板的模板参数可以用来声明成员变量和成员函数。成员函数可以用在类内实现,也可以在类外实现,和普通类一样,在类外实现时,要指定作用成员函数的作用域,只不过类的类型时mystack<T>,所以拷贝构造函数和operator=的形参类型都是mystack<T>的引用,作用域也因此是mystack<T>,因为有模板参数,所以,成员函数在类外实现时也要加template关键字和模板参数列表(template <typename T>)
二、使用类模板
int main(int argc, char const *argv[])
{
mystack<int> si;
return 0;
}

当实例化一个类模板时,没有报错,正常输出,但是在main函数中添加si.push(10);后,编译器提示以下错误

原因是形参elem没有push_back操作,形参和成员变量重名了,修改后,输出结果如下

也就是说,上述代码中的类成员函数在调用之前,没报错,被调用后,成员函数报错了,所以,对于类模板来说,成员函数只有在被调用的时候才会实例化,而实例化相关的错误只有在实例化时才会出现,在编译模板本身时并不会出现。类模板的成员函数只有在被调用时才会实例化可以节省空间和时间
三、类模板的特化
有时候,通用的类模板对于某些模板实参可能并不适合,这时候就需要对类模板进行特化。特化一个类模板是需要在其起始处添加template<>,然后接下来声明特化类模板的类型
示例
template<>
class mystack<string>
{
public:
mystack();
mystack(const mystack<string> &rval);
mystack<string> &operator=(const mystack<string> &rval);
~mystack();
void push(const string& ele);
void pop();
string top() const;
bool empty() const {
return elem.empty();
}
private:
deque<string> elem;
};
mystack<string>::mystack()
{
cout<<__func__<<endl;
}
mystack<string>::mystack(const mystack<string> &rval):elem(rval.elem)
{
cout<<__func__<<endl;
}
mystack<string> & mystack<string>::operator=(const mystack<string> &rval)
{
cout<<__func__<<endl;
if (this==&rval) {
return *this;
}
this->elem=rval.elem;
return *this;
}
mystack<string>::~mystack()
{
cout<<__func__<<endl;
}
void mystack<string>::push(const string &ele)
{
cout<<__func__<<endl;
elem.push_back(ele);
}
void mystack<string>::pop()
{
cout<<__func__<<endl;
try {
elem.pop_back();
}
catch (out_of_range &e){
cout<<"out_of_range"<<endl;
}
}
string mystack<string>::top() const
{
cout<<__func__<<endl;
try {
return elem.back();
}
catch (out_of_range &e){
cout<<"out_of_range"<<endl;
}
return "";
}
上述代码就是mystack的特化版本,大体上和类模板mystack没差多少,但是容器类型从vector变为deque,捕获异常的方式也变成捕获异常的引用,如果仍然按照类模板的代码,会出警告

上述情况说明:1、特化版本的模板类可以和原来的类模板完全不同。2、特化类模板之后,会出现编译原先类模板时不曾出现的错误,所以类模板的特化本质依旧是类模板的实例化
特化只是一种特殊的实例化,但是实例化的方式并不只有特化这一种
参考
《C++ Template》
《C++ Primer》
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出
本文围绕C++类模板展开,介绍了类模板通过template关键字声明和定义,成员函数可在类内或类外实现。指出类模板成员函数只有在被调用时才会实例化,能节省时空。还阐述了类模板特化,即对某些模板实参不适用时进行特化,特化本质是特殊的实例化。
314

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



