1. 什么是类模板?
在 C++ 中,类模板(Class Template) 是一种定义类的通用方式,它允许我们在定义类时将类型(Type)或数值参数化,这样同一份代码可以适配不同的数据类型和常量值,从而提高代码的 复用性 和 灵活性。
类模板的定义语法一般为:
template <typename T>
class ClassName {
// 类成员定义
};
其中,typename
(或 class
)引入了一个类型参数 T
,在实例化时由用户指定具体的类型。
2. 类模板的参数类型
类模板参数主要分为三类:
2.1 类型参数(Type Parameter)
这是最常用的模板参数类型,用来在编译期间传入类型。
示例:
#include <iostream>
using namespace std;
template <typename T>
class MyContainer {
private:
T data;
public:
MyContainer(T value) : data(value) {}
void show() { cout << data << endl; }
};
int main() {
MyContainer<int> c1(42); // 传入 int 类型
MyContainer<string> c2("Hi"); // 传入 std::string 类型
c1.show(); // 输出 42
c2.show(); // 输出 Hi
}
说明:
T
是类型参数,在实例化类时会被替换成实际类型。- 实例化时
MyContainer<int>
和MyContainer<string>
是两个不同的类类型。
2.2 非类型参数(Non-type Parameter)
除了类型参数,模板也可以接受常量作为参数,比如整型、枚举、指针等(C++20 之后也可以用浮点数、字符串字面量)。
示例:
#include <iostream>
using namespace std;
template <typename T, int Size>
class Array {
private:
T arr[Size];
public:
void set(int index, T value) {
if (index >= 0 && index < Size) {
arr[index] = value;
}
}
void display() {
for (int i = 0; i < Size; ++i) {
cout << arr[i] << " ";
}
cout << endl;
}
};
int main() {
Array<int, 5> arr1; // int 类型, 数组大小为 5
arr1.set(0, 100);
arr1.set(1, 200);
arr1.display(); // 输出:100 200 0 0 0
}
说明:
- 第二个模板参数
Size
是编译期常量(这里是int
),用来定义数组大小。 - 非类型模板参数必须是编译期已知的常量。
2.3 模板模板参数(Template Template Parameter)
模板参数本身也可以是一个模板,比如容器类中使用的容器类型就可以作为参数。
示例:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
template <template <typename, typename> class Container, typename T>
class DataHolder {
private:
Container<T, allocator<T>> data;
public:
void add(const T& value) { data.push_back(value); }
void show() {
for (const auto& item : data)
cout << item << " ";
cout << endl;
}
};
int main() {
DataHolder<vector, int> vHolder; // 使用 vector
DataHolder<list, int> lHolder; // 使用 list
vHolder.add(1);
vHolder.add(2);
vHolder.show(); // 输出:1 2
lHolder.add(3);
lHolder.add(4);
lHolder.show(); // 输出:3 4
}
说明:
- 第一个模板参数
Container
本身是一个模板(如std::vector
)。 - 必须完整写出
template <typename, typename>
来匹配容器的模板定义。
3. 类模板的默认参数
类模板的参数和函数一样,可以有默认值。
示例:
#include <iostream>
using namespace std;
template <typename T = int, int Size = 10>
class FixedArray {
private:
T arr[Size];
public:
void fill(const T& value) {
for (int i = 0; i < Size; ++i)
arr[i] = value;
}
void show() {
for (int i = 0; i < Size; ++i)
cout << arr[i] << " ";
cout << endl;
}
};
int main() {
FixedArray<> a1; // 使用默认 T=int, Size=10
FixedArray<double, 5> a2; // 自定义类型和大小
a1.fill(7);
a1.show();
a2.fill(3.14);
a2.show();
}
4. 部分特化(Partial Specialization)
有时我们希望针对某种特定的模板参数组合提供特殊实现,这时可以使用类模板特化。
示例:
#include <iostream>
using namespace std;
template <typename T, typename U>
class MyPair {
public:
void show() {
cout << "General template" << endl;
}
};
// 针对第二个参数为 int 的特化
template <typename T>
class MyPair<T, int> {
public:
void show() {
cout << "Specialized for second parameter int" << endl;
}
};
int main() {
MyPair<double, char> p1;
MyPair<float, int> p2;
p1.show(); // General template
p2.show(); // Specialized for second parameter int
}
5. 总结
类模板参数的灵活性让我们能够编写高度通用的类:
- 类型参数(
typename T
)是最常用的,适用于泛型数据结构。 - 非类型参数可以让结构在编译期固定某些常量,提升性能和安全性。
- 模板模板参数适用于设计可接受不同容器或其他模板的泛型类。
- 类模板也支持默认参数、特化和部分特化,让我们可以针对特定需求优化实现。
如果你希望在项目中写出高可复用性的代码,理解并灵活运用类模板参数将大有裨益。