C++ 模板

模板是C++中泛型编程的基础。一个模板就是一个创建类或函数的公式,使用模板能够让程序员编写与类型无关的代码。

函数模板

假定我们希望编写一个函数来比较两个值的大小,由于C++语言定义函数或变量时都必须确定其数据类型,因此对于不同的数据类型,比较函数都必须定义一份,以int、double和string为例:

int compare(const int &v1, const int &v2)
{
	if (v1 < v2)	return -1;
	else if (v2 < v1)	return 1;
	return 0;
}

int compare(const double &v1, const double &v2)
{
	if (v1 < v2)	return -1;
	else if (v2 < v1)	return 1;
	return 0;
}

int compare(const string &v1, const string &v2)
{
	if (v1 < v2)	return -1;
	else if (v2 < v1)	return 1;
	return 0;
}

上述通过定义多个重载函数实现大小比较的方式可看出,每个函数几乎是相同的,唯一的差异是参数的类型,函数体则完全一样。如果希望对每种数据类型数据大小比较不再重复定义与上述三种类型完全一样的函数体,我们就需要使用函数模板,这样就不需要为每种数据类型都定义一个新函数了。对于上述compare函数,其函数模板可定义为:

template <typename T>
int compare(const T &v1, const T &v2)
{
	if (v1 < v2)	return -1;
	else if (v2 < v1)	return 1;
	return 0;
}

模板定义以关键字template开始,后跟一个模板参数列表(逗号分隔的一个或多个模板参数),关键字typename可用class代替,不过通常建议优先选用typename。
下面编写一个类似标准库find算法的模板,需要两个模板类型参数,一个表示迭代器参数,另一个表示数据类型参数,其模板定义如下:

template <typename InputIt, typename T>
InputIt find(InputIt begin, InputIt end, const T& value)
{
	for (; begin != end; ++begin)
	{
		if (value == *begin)
		{
			return begin;
		}
	}

	return end;
}

对于上述compare和find函数,其调用方式可参考如下:

int main() {
	cout << compare(1, 2) << endl;
	cout << compare(3.5, 2.7) << endl;

	vector<int> intVector;
	intVector.push_back(1);
	intVector.push_back(0);
	vector<int>::iterator it = find(intVector.begin(), intVector.end(), 0);
	if (intVector.end() == it)
	{
		cout << "find nothing" << endl;
	}
	else
	{
		int n = it - intVector.begin();
		cout << "find it, it=" << n << endl;
	}
	system("pause");
	return 0;
}

类模板

类模板可用于表示一组类,这些类仅仅是成员变量类型不同,但对成员变量的操作类似。
下面以Stack为例进行类模板的演示,使用模板参数T声明成员变量,栈中可存储各种数据类型,不需要为每一种数据类型都写一个这样的类。

template <typename T> 
class Stack{
public:
	Stack(int s = 10);
	~Stack();

	int push(const T&);  //入栈(添加元素)
	int pop(T&);		 //出栈(删除元素)
	int isEmpty() const;
	int isFull() const;
	void printAll();

private:
	int size;  //栈大小
	int top;   //顶部元素位置
	T* stackPtr; //存储数据指针
};

//模板类的每一个成员函数都是模板函数,需要在没一个函数实现前加模板参数声明
template <typename T> 
Stack<T>::Stack(int s)
:size(s), top(-1), stackPtr(NULL)
{
	stackPtr = new T[size];
}

template <typename T> 
Stack<T>::~Stack()
{
	delete []stackPtr;
	stackPtr = NULL;
}

template <typename T> 
int Stack<T>::push(const T& value)
{
	if (isFull())
		return -1;
	stackPtr[++top] = value;
	return 0;
}

template <typename T> 
int Stack<T>::pop(T& value)
{
	if (isEmpty())
		return -1;
	value = stackPtr[top--];
	return 0;
}

template <typename T> 
int Stack<T>::isEmpty() const
{
	return -1 == top;
}

template <typename T> 
int Stack<T>::isFull() const
{
	return size - 1 == top;
}

template <typename T> 
void Stack<T>::printAll()
{
	if (isEmpty())
	{
		cout << "no element in Stack" << endl;
		return;
	}

	for (int i = 0; i <= top; ++i)
		cout << stackPtr[i] << " ";
	cout << endl;
}

类似函数模板,类模板以关键字template开始,后跟模板参数列表。在类模板(及其成员)的定义中,我们将模板参数当做替身,代替使用模板时用户需要提供的类型或值。
与函数模板不同的是,编译器不能为类模板推断模板参数类型,为了使用类模板,必须在模板名后的尖括号中提供type信息—用来代替模板参数的模板实参列表。调用Stack模板类的方法参考如下:

int main() {
	//类模板在声明该模板的对象时,必须明确对模板参数实例化
	Stack<int> stack_int; //实例化T为int类型
	stack_int.push(12);
	stack_int.push(34);
	cout << "push 12 and 34, printAll:" << endl;
	stack_int.printAll();
	int popEle = -1;
	stack_int.pop(popEle);
	cout << "pop one = " << popEle << endl;
	cout << "printAll:" << endl;
	stack_int.printAll();
	stack_int.pop(popEle);
	cout << "pop one = " << popEle << endl;
	cout << "printAll:" << endl;
	stack_int.printAll();

	system("pause");
	return 0;
}

运行结果如下:
在这里插入图片描述
上述代码只实例化了存储int类型数据的Stack,读者可自行进行存储其他类型数据的Stack的实例化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值