模板类的核心就是:把类里的数据类型参数化 ,让同一个类能处理 int、double、string 等各种类型。
基本写法
cpp
1template <typename T> // 声明模板参数 T
2class Stack {
3public:
4 Stack(int capacity = 4)
5 : _array(new T[capacity])
6 , _top(0)
7 , _capacity(capacity)
8 {}
9
10 ~Stack() {
11 delete[] _array;
12 }
13
14 void Push(const T& x) {
15 _array[_top++] = x;
16 }
17
18 T Top() const {
19 return _array[_top - 1];
20 }
21
22private:
23 T* _array;
24 int _top;
25 int _capacity;
26};
使用时:
cpp
1Stack<int> s1; // int 版本的栈
2Stack<double> s2; // double 版本的栈
3Stack<std::string> s3; // string 版本的栈
成员函数在类外定义
模板类的成员函数如果在类外定义,每个函数前面都要加 template<typename T>:
cpp
1template <typename T>
2void Stack<T>::Push(const T& x) {
3 _array[_top++] = x;
4}
5
6template <typename T>
7T Stack<T>::Top() const {
8 return _array[_top - 1];
9}
注意类名要写成 Stack<T>,不能只写 Stack。
多个模板参数
cpp
1template <typename K, typename V>
2class HashMap {
3 // ...
4};
5
6HashMap<std::string, int> map;
模板参数也可以是非类型参数
cpp
1template <typename T, int N>
2class Array {
3 T _data[N]; // N 是编译期常量
4};
5
6Array<int, 10> arr; // 大小为 10 的 int 数组
关键特性
- 模板不是类 ,它只是一个"蓝图"。只有当你写
Stack<int>时,编译器才会根据模板实例化 出一个真正的Stack<int>类。 - 模板的定义(声明+实现)通常要放在头文件(.h/.hpp) 里,不能像普通类那样把声明放 .h、定义放 .cpp,否则链接时会报错(因为编译器在别的翻译单元看不到模板定义,无法实例化)。
typename和class在这里等价,但习惯上类型参数用typename,模板模板参数用class。
拓展
类名<T> vs 类名
| 场景 | 写法 | 示例 |
|---|---|---|
| 使用模板类(实例化) | 必须写 <T> |
Stack<int> s; |
| 类内写成员函数 | 直接写类名 | void Push(const T& x); |
| 类外定义成员函数 | 必须写 Stack<T>:: |
void Stack<T>::Push(...) |
| 模板类内部引用自身 | 可以只写类名 | Stack* _next; |
| 友元、继承、typedef | 通常需要 <T> |
friend class Iterator<T>; |
本质理解
Stack 不是类,它只是一个模板。
Stack<int>、Stack<double> 才是真正的类(编译器根据模板实例化出来的)。
所以:
cpp
1template <typename T>
2class Stack {
3public:
4 void Push(const T& x); // 类内,直接写类名就行
5};
6
7// 类外定义,必须带 <T>
8template <typename T>
9void Stack<T>::Push(const T& x) { ... }
10// ^^^^^^^^ 这里必须写 Stack<T>
11
12// 使用时,必须带 <T>
13Stack<int> s; // ✅
14Stack s; // ❌ 编译报错,Stack 不是类
C++17 的例外:类模板参数推导(CTAD)
从 C++17 开始,如果你提供了构造函数,编译器可以自动推导类型:
cpp
1template <typename T>
2class Stack {
3public:
4 Stack(const T& val) { ... }
5};
6
7Stack s(42); // ✅ C++17 起合法,自动推导为 Stack<int>
但这只是语法糖,底层还是 Stack<int>。
简单记:只要你在"使用"一个模板类,就必须带上 <类型>;只有在模板类自己的定义内部,才可以省略。