定义模板类

先看一个之前自定义的Stack类

// 别名
typedef unsigned long Item;

class Stack
{
private:
	enum {MAX = 10};
	Item items[MAX];
	int top;
	
public:
	Stack();
	bool isempty() const;
	bool isfull() const;
	bool push(const Item & item);
	bool pop(Item & item);
};

模板类以下面这样的代码开头:

template <class Type>

关键字template告诉编译器, 将要定义一个模板, 尖括号中的内容相当于函数的参数列表. 可以把关键字class看作是变量的类型名, 该变量接收类型作为其值, 把Type看做是该变量的名称.

这里的class并不意味着Type必须是一个类, 而只是表明Type是一个通用的类型说明符, 在使用模板时, 将使用实际的 类型替换它, 也可以使用typename替换class:

template <typename Type>

同样, 可以使用模板成员函数替换原有类的类方法. 每个函数头都将以相同的模板声明打头:

template <class Type>

同样应使用泛型名Type(可以替换成T等其他字符)替换typedef标识符Item, 另外, 还需要将类限定符从Stack::改为Stack<Type>::, 例如:

bool Stack::push(const Item & item)
{
	...
}

应改为:

template <class Type>
bool Stack<Type>::push(const Type & item)
{
    ...
}

如果在类声明中定义了方法(内联定义), 则可以省略模板前缀和类限定符.

模板的具体实现--如:用来处理string对象的栈类被称为实例化(instantiation)或具体化(specialization). 不能将模板成员函数放在独立的实现文件中. 由于模板不是函数, 他们不能单独编译, 模板必须与特定的模板实例化请求一起使用. 因此最简单的方法是将所有模板信息放在一个头文件中, 并在要使用这些模板的肯建中包含该头文件:

看一个完整的例子:

// stacktp.h
#ifndef STACKTP_H_
#define STACKTP_H_

// 模板类
template <class Type>
class Stack
{
private:
	enum {MAX = 10};
	Type items[MAX];
	int top;
public:
	Stack();
	bool isempty();
	bool isfull();
	bool push(const Type & tiem);
	bool pop(Type & item);
};

// 模板方法:
template <class Type>
Stack<Type>::Stack()
{
	top = 0;
}

template <class Type>
bool Stack<Type>::isempty()
{
	return top == 0;
}

template <class Type>
bool Stack<Type>::isfull() 
{
	return top == MAX;
}

template <class Type>
bool Stack<Type>::push(const Type & item)
{
	if (top < MAX)
	{
		items[top++] = item;
		return true;
	} else {
		return false;
	}
}

template <class Type>
bool Stack<Type>::pop(Type & item)
{
	if(top > 0)
	{
		item = items[--top];
		return true;
	} else {
		return false;
	}
}

#endif

使用Stack模板类:

// 创建一个int型的Stack
Stack<int> kernels;

// 创建一个string类型的Stack对象
Stack<string> colonels;

调用模板类的文件: 

// 使用Stack模板类
// stacktem.cpp
#include <iostream>
#include <string>
#include <cctype>
#include "stacktp.h"

using std::cin;
using std::cout;
using std::endl;

int main()
{
	Stack<std::string> st;
	char ch;
	std::string po;
	cout << "Please enter A to add a purchase order, " << endl;
	cout << "P to process a PO, or Q to quit." << endl;
	
	while(cin >> ch && std::toupper(ch) != 'Q')
	{
		while(cin.get() != '\n')
			continue;
		if(!std::isalpha(ch))
		{
			cout << '\a';
			continue;
		}
		switch(ch)
		{
			case 'A':
			case 'a':
				cout << "Enter a PO number to add: ";
				cin >> po;
				if(st.isfull())
					cout << "stack already full" << endl;
				else 
					st.push(po);
				break;
				
			case 'p':
			case 'P':
				if(st.isempty())
					cout << "stack already empty" << endl;
				else {
					st.pop(po);
					cout << "PO #" << po << " popped" << endl;
				}
				break;
		}
		cout << "Please enter A to add a purchase order, P to process a PO, or Q to quit" << endl;
	}
	cout << "Bye" << endl;
	return 0;
}

程序运行结果为:

C++ Primer Plus 书之--C++ 模板类

相关文章: