在 C++ 面向对象编程中,类模板(Class Template) 是实现代码复用 和类型通用化 的核心特性。它允许我们定义一个 "通用模板",不指定具体数据类型,而是用类型参数占位,使用时再根据需要绑定具体类型(如 int、double、自定义类),自动生成对应类型的类。
简单来说:类模板是创建类的模具,类型是模具的参数,不同类型能快速生成不同的专属类,无需重复编写代码。
一、为什么需要类模板?
面向对象编程中,我们常需要为不同数据类型实现相同的逻辑功能。例如:
一个整数栈(int Stack)
一个浮点数栈(double Stack)
一个字符串栈(string Stack)
如果不使用类模板,需要为每种类型单独写一个类,代码高度冗余、难以维护。类模板完美解决了这个问题:只写一套通用代码,编译器自动为不同类型生成对应的类,兼顾通用性和类型安全。
二、类模板的基础语法
1. 定义格式
类模板以template关键字开头,后跟类型参数列表,语法固定:
cpp
// template:声明模板关键字
// <typename T>:模板参数列表,T是类型参数(可自定义名称,如Type、E)
// typename 也可以用 class 替代,效果完全一致
template <typename T>
class 类名 {
// 类的成员变量、成员函数,都可以使用类型参数T
private:
T data; // T是占位类型,使用时才确定具体类型
public:
// 成员函数中使用T作为参数、返回值类型
void setData(T value);
T getData();
};
2. 核心规则
- 模板参数可以是类型参数 (用
typename/class声明),也可以是非类型参数(如常量 int); - 类模板的成员函数,如果在类外定义,必须也声明为模板;
- 类模板本身不是真正的类,实例化后才会生成具体的类(称为模板类)。
三、类模板的完整实现:以通用栈为例
栈(Stack)是经典的线性结构,核心操作是入栈、出栈、判空。我们用类模板实现支持任意类型的栈:
cpp
#include <iostream>
// 定义类模板:通用栈
template <typename T> // T为类型参数,代表栈存储的数据类型
class Stack {
private:
T* arr; // 动态数组存储元素,类型为T
int topIndex; // 栈顶索引
int capacity; // 栈容量
public:
// 构造函数
Stack(int cap = 10) {
capacity = cap;
topIndex = -1;
arr = new T[capacity]; // 动态分配T类型数组
}
// 析构函数
~Stack() {
delete[] arr;
}
// 入栈:参数类型为T
void push(T value) {
if (topIndex == capacity - 1) {
std::cout << "栈已满!" << std::endl;
return;
}
arr[++topIndex] = value;
}
// 出栈:返回值类型为T
T pop() {
if (topIndex == -1) {
std::cout << "栈为空!" << std::endl;
// 返回T类型默认值,保证类型匹配
return T();
}
return arr[topIndex--];
}
// 获取栈顶元素
T getTop() {
if (topIndex == -1) return T();
return arr[topIndex];
}
// 判断栈是否为空
bool isEmpty() {
return topIndex == -1;
}
};
四、类模板的实例化与使用
类模板本身不是可直接使用的类,必须指定具体类型进行实例化,编译器才会生成真正的类。
1. 实例化语法
cpp
// 类模板名<具体类型> 对象名;
Stack<int> intStack; // 整数栈(T绑定为int)
Stack<double> doubleStack; // 浮点数栈(T绑定为double)
Stack<std::string> strStack; // 字符串栈(T绑定为string)
- 调用示例
cpp
int main() {
// 1. 使用int类型栈
Stack<int> s1(5);
s1.push(10);
s1.push(20);
std::cout << "int栈出栈:" << s1.pop() << std::endl; // 输出20
// 2. 使用string类型栈
Stack<std::string> s2;
s2.push("Hello");
s2.push("C++ Template");
std::cout << "string栈出栈:" << s2.pop() << std::endl; // 输出C++ Template
return 0;
}
运行结果:
cpp
int栈出栈:20
string栈出栈:C++ Template
五、类外实现成员函数(重点)
如果将类模板的成员函数写在类外部,必须遵循模板语法,否则编译报错:
cpp
template <typename T> // 必须重新声明模板参数
返回值类型 类名<T>::函数名(参数列表) {
// 函数实现
}
示例:将栈的push函数类外实现:
cpp
template <typename T>
void Stack<T>::push(T value) {
if (topIndex == capacity - 1) {
std::cout << "栈已满!" << std::endl;
return;
}
arr[++topIndex] = value;
}
注意:必须写
Stack<T>,不能只写Stack,因为Stack是模板,Stack<T>才是具体的类。
六、类模板的高级特性
1. 多参数类模板
一个类模板可以声明多个类型参数,适配更复杂的场景:
cpp
// 两个类型参数:T1、T2
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
void set(T1 a, T2 b) {
first = a;
second = b;
}
void show() {
std::cout << first << ", " << second << std::endl;
}
};
// 使用:int + string 组合
Pair<int, std::string> p;
p.set(100, "成绩");
p.show(); // 输出:100, 成绩
2. 非类型模板参数
除了类型参数,类模板还支持常量参数(如整数、指针):
cpp
// N是非类型参数(整数常量),指定数组大小
template <typename T, int N>
class Array {
private:
T arr[N]; // 固定大小的数组
public:
void set(int index, T value) {
if (index >= 0 && index < N) arr[index] = value;
}
};
// 使用:存储5个int的数组
Array<int, 5> arr;
arr.set(0, 10);
3. 类模板的特化
特化:为特定类型单独编写模板实现,覆盖通用模板逻辑。
全特化:为所有类型参数指定具体类型;
偏特化:为部分类型参数指定具体类型(仅类模板支持)。
全特化示例 :为char*类型单独实现栈:
cpp
// 通用模板
template <typename T>
class Demo {
public:
void show() {
std::cout << "通用模板" << std::endl;
}
};
// 全特化:T绑定为char*
template <>
class Demo<char*> {
public:
void show() {
std::cout << "char*类型特化模板" << std::endl;
}
};
// 使用
Demo<int> d1; d1.show(); // 通用模板
Demo<char*> d2; d2.show(); // char*类型特化模板
七、类模板的核心注意事项
- 编译期实例化 :类模板的代码在编译时生成,不是运行时,因此效率高;
- 代码分离问题 :类模板的声明和实现建议写在同一个头文件(.h) 中,分开写会导致链接报错(编译器无法找到模板实现);
- 类型安全:实例化后严格匹配类型,不会出现类型隐式转换错误;
- 与函数模板的区别 :类模板是对类 的通用化,函数模板是对函数的通用化,都是 C++ 泛型编程的基础。
八、类模板的应用场景
在 C++ 开发中,类模板是标准库的核心基础,我们常用的容器都是类模板实现:
std::vector<T>(动态数组)
std::list<T>(链表)
std::map<T1, T2>(键值对映射)
实际开发中,自定义通用工具类(如通用队列、通用链表、通用数据处理器)都依赖类模板。
总结
- 类模板本质:带类型参数的类模具,实现代码通用化,避免重复编写相同逻辑;
- 核心语法 :
template <typename T>声明,使用时指定具体类型; - 关键用法:成员函数类外实现需带模板声明,支持多参数、特化;
- 核心价值:兼顾代码复用、类型安全、开发效率,是 C++ 面向对象与泛型编程的结合点。
掌握类模板,是从基础面向对象编程进阶到通用化、工程化 C++ 开发的关键一步。