一、类模板核心概念
类模板是C++泛型编程的基石,它允许我们定义类型无关的类。与函数模板不同,类模板的实例化需要显式指定类型参数。通过类模板可以实现:
-
通用容器(如vector、list)
-
泛型数据结构(栈、队列、树)
-
数学对象(矩阵、向量)
-
智能指针(unique_ptr、shared_ptr)
二、基本语法与实例化
1. 基本声明格式
template <typename T> // 模板参数列表
class MyContainer {
public:
void add(const T& element);
T get(int index);
private:
T* data;
int size;
};
2. 成员函数定义
template <typename T> // 每个成员函数都需要模板声明
void MyContainer<T>::add(const T& element) {
// 实现代码
}
3. 实例化类模板
MyContainer<int> intContainer; // 存储int类型
MyContainer<string> strContainer; // 存储string类型
三、经典案例:动态数组实现
1. 类模板声明
template <typename T>
class DynamicArray {
public:
explicit DynamicArray(size_t initialSize = 10);
~DynamicArray();
void push_back(const T& value);
T& operator[](size_t index);
const T& operator[](size_t index) const;
size_t size() const;
private:
T* m_data;
size_t m_size;
size_t m_capacity;
};
2. 方法实现
template <typename T>
DynamicArray<T>::DynamicArray(size_t initialSize)
: m_data(new T[initialSize]),
m_size(0),
m_capacity(initialSize) {}
template <typename T>
void DynamicArray<T>::push_back(const T& value) {
if (m_size >= m_capacity) {
// 扩容逻辑
T* newData = new T[m_capacity * 2];
std::copy(m_data, m_data + m_size, newData);
delete[] m_data;
m_data = newData;
m_capacity *= 2;
}
m_data[m_size++] = value;
}
四、高级特性详解
1. 多类型参数
template <typename Key, typename Value>
class HashMap {
public:
void insert(const Key& k, const Value& v);
Value& get(const Key& k);
// ...
};
2. 非类型模板参数
template <typename T, size_t N> // N是非类型参数
class FixedArray {
public:
T& operator[](size_t index) {
if (index >= N) throw out_of_range("...");
return m_data[index];
}
private:
T m_data[N];
};
FixedArray<double, 100> sensorData; // 固定大小数组
3. 模板特化
// 通用版本
template <typename T>
class Comparator {
public:
bool compare(const T& a, const T& b) {
return a < b;
}
};
// 特化版本(针对char*)
template <>
class Comparator<const char*> {
public:
bool compare(const char* a, const char* b) {
return strcmp(a, b) < 0;
}
};
4. 继承中的模板
template <typename T>
class Base {
public:
void baseMethod() { /*...*/ }
};
template <typename U>
class Derived : public Base<U> {
public:
void derivedMethod() {
this->baseMethod(); // 需要显式使用this或Base<U>::
}
};
五、STL中的类模板应用
STL组件 | 模板参数 | 功能描述 |
---|---|---|
vector<T> | 元素类型T | 动态数组 |
map<Key,Value> | 键类型Key,值类型Value | 关联容器 |
shared_ptr<T> | 指向类型T | 智能指针 |
tuple<T...> | 任意多个类型参数 | 异构元组 |
function<R(A)> | 返回类型R,参数类型A | 函数包装器 |
六、最佳实践指南
-
头文件组织
类模板的定义和实现必须放在头文件中(编译器需要看到完整定义) -
类型别名优化
使用using
简化复杂类型template <typename T> class Matrix { public: using Iterator = typename std::vector<T>::iterator; // ... };
-
友元函数处理
声明友元需要特别注意模板参数template <typename U> friend std::ostream& operator<<(std::ostream&, const Matrix<U>&);
-
静态成员处理
每个模板实例都有独立的静态成员template <typename T> class MyClass { public: static int count; // 每个MyClass<T>有独立count }; template <typename T> int MyClass<T>::count = 0;
七、C++17新特性:类模板参数推导(CTAD)
template <typename T>
class Box {
public:
Box(T content) : m_content(content) {}
private:
T m_content;
};
// 传统方式
Box<int> intBox(42);
// C++17推导指引
Box doubleBox(3.14); // 自动推导为Box<double>
Box stringBox("hello"); // 推导为Box<const char*>
// 自定义推导规则
template <typename T>
Box(T) -> Box<std::decay_t<T>>;
八、典型应用场景
1. 泛型工厂模式
template <typename ProductType>
class Factory {
public:
static ProductType* create() {
return new ProductType();
}
};
// 使用示例
auto car = Factory<Car>::create();
2. 数学矩阵运算
template <typename T, size_t ROWS, size_t COLS>
class Matrix {
public:
Matrix operator+(const Matrix& other) const;
Matrix operator*(const Matrix& other) const;
// ...
private:
T m_data[ROWS][COLS];
};
九、常见问题解答
Q:为什么类模板成员函数定义必须写在头文件里?
A:模板需要在编译时实例化,分离定义会导致链接错误
Q:如何限制类模板的类型参数?
A:C++20前使用static_assert,C++20可使用concepts
template <typename T>
class Number {
static_assert(std::is_arithmetic_v<T>,
"T必须是数值类型");
};
Q:模板类能否作为基类?
A:可以,但派生类需要正确处理模板参数传递
Q:如何实现模板类的拷贝控制?
A:与普通类相同,但要注意模板参数类型
template <typename T>
class MyClass {
public:
MyClass(const MyClass& other) { /*...*/ }
MyClass& operator=(const MyClass& other) { /*...*/ }
};