C++知识点56——类模板(1、模板类的介绍)

本文围绕C++类模板展开,介绍了类模板通过template关键字声明和定义,成员函数可在类内或类外实现。指出类模板成员函数只有在被调用时才会实例化,能节省时空。还阐述了类模板特化,即对某些模板实参不适用时进行特化,特化本质是特殊的实例化。

一、类模板

和函数模板一样,类模板也得通过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》

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值