6.6 类模板
类模板是C++语言支持参数化的一种工具,旨在实现代码重用,使代码能够适应不同的数据类型和操作。类模板允许我们定义具有某些数据成员和成员函数的类,这些数据成员和成员函数可以使用多种类型,从而提高代码的通用性和重用性。
6.6.1 类模板的引入
引入类模板的目的是为了更好地进行代码重用,避免为每种数据类型重复编写相同的代码。类模板允许我们创建一个通用的类,这个类可以处理不同类型的数据。下面通过一个链表类的例子来说明类模板的必要性。
示例:链表类
非模板实现
class Node {
// 结点类的定义
};
class List {
public:
List();
~List();
void Add(Node &);
void Remove(Node &);
Node* Find(Node &);
};
这个链表类只能处理Node
类型的结点。如果我们需要处理其他类型的结点,就需要重新定义链表类,这会导致代码的重复和维护的复杂性。
使用模板实现
通过引入类模板,可以使链表类通用化:
template <typename T>
class List {
public:
List();
~List();
void Add(T &);
void Remove(T &);
T* Find(T &);
};
在这个类模板中,使用了一个参数化的类型T
,它被用作成员函数参数的类型。这样,链表类可以处理任何类型的结点,显著提高了代码的重用性和灵活性。
6.6.2 类模板和模板类
类模板的定义格式
类模板的定义格式如下:
template <typename T>
class 类名 {
// 类体
};
template
关键字用于定义类模板,<typename T>
表示模板参数。模板参数可以有多个,用逗号分隔。
示例:有界数组的类模板
template <typename AType>
class Array {
public:
Array(int size);
~Array() { delete[] a; }
AType& operator[](int i);
private:
int length;
AType* a;
};
template <typename AType>
Array<AType>::Array(int size) {
length = size;
a = new AType[size];
for (int i = 0; i < size; i++) {
a[i] = 0;
}
}
template <typename AType>
AType& Array<AType>::operator[](int i) {
if (i < 0 || i >= length) {
std::cerr << "Index out-of-bounds.\n";
exit(1);
}
return a[i];
}
定义类模板时需要注意以下几点:
- 使用
template
关键字。 - 确定至少一个模板参数,多个模板参数用逗号分隔。
- 类模板中的成员函数可以是函数模板。
模板类
在定义了类模板之后,系统会根据需要生成相应的模板类。例如,使用Array<int>
和Array<double>
分别生成int
型和double
型的模板类。
示例:使用模板类
#include <iostream>
#include "Array.h"
int main() {
Array<int> intArray(10);
Array<double> doubleArray(5);
for (int i = 0; i < 10; i++) {
intArray[i] = i + 1;
}
for (int i = 0; i < 5; i++) {
doubleArray[i] = (i + 1) * 3.14;
}
std::cout << "Integer array: ";
for (int i = 0; i < 10; i++) {
std::cout << intArray[i] << " ";
}
std::cout << std::endl;
std::cout << "Double array: ";
for (int i = 0; i < 5; i++) {
std::cout << doubleArray[i] << " ";
}
std::cout << std::endl;
return 0;
}
通过使用类模板,可以创建适用于不同数据类型的数组,并对其进行操作。
6.6.3 类模板应用举例
类模板在实际编程中应用广泛,可以显著提高代码的重用性。下面是一个栈的类模板的示例。
示例:栈的类模板
#include <iostream>
#include <cstdlib>
template <typename T>
class Stack {
public:
Stack(int size);
~Stack() { delete[] stack; }
void push(T i);
T pop();
private:
int tos;
int length;
T* stack;
};
template <typename T>
Stack<T>::Stack(int size) {
stack = new T[size];
if (!stack) {
std::cerr << "Cannot allocate stack.\n";
exit(1);
}
length = size;
tos = 0;
}
template <typename T>
void Stack<T>::push(T i) {
if (tos == length) {
std::cerr << "Stack is full.\n";
return;
}
stack[tos++] = i;
}
template <typename T>
T Stack<T>::pop() {
if (tos == 0) {
std::cerr << "Stack underflow.\n";
exit(1);
}
return stack[--tos];
}
int main() {
Stack<int> intStack(10);
Stack<double> doubleStack(10);
Stack<char> charStack(10);
intStack.push(15);
doubleStack.push(18.1);
intStack.push(18);
intStack.push(14);
doubleStack.push(3.14);
std::cout << intStack.pop() << ", ";
std::cout << intStack.pop() << ", ";
std::cout << intStack.pop() << std::endl;
std::cout << doubleStack.pop() << ", ";
std::cout << doubleStack.pop() << std::endl;
for (int i = 0; i < 10; i++) {
charStack.push('A' + i);
}
for (int i = 0; i < 10; i++) {
std::cout << charStack.pop();
}
std::cout << std::endl;
return 0;
}
执行该程序,输出结果如下:
14, 18, 15
3.14, 18.1
JIHGFEDCBA
这个例子展示了如何使用类模板来创建和操作不同类型的栈,提高了代码的重用性和灵活性。