1. 类模板的基本概念
什么是类模板?
类模板是能够根据不同数据类型生成不同类的"蓝图"。
生活比喻:
text
做饼干的模具:
- 同一个模具,可以用面粉做饼干
- 也可以用巧克力做饼干
- 模具是模板,具体的饼干是实例化的类
2. 基本语法
2.1 最简单的类模板
cpp
#include <iostream>
// 声明类模板
template<typename T> // T 是类型参数
class Box {
private:
T content;
public:
Box(const T& item) : content(item) {}
T getContent() const {
return content;
}
void setContent(const T& item) {
content = item;
}
void show() const {
std::cout << "Box contains: " << content << std::endl;
}
};
2.2 使用类模板
cpp
void basicTemplateDemo() {
std::cout << "=== 基本类模板使用 ===" << std::endl;
// 实例化为 int 类型
Box<int> intBox(42);
intBox.show();
// 实例化为 double 类型
Box<double> doubleBox(3.14);
doubleBox.show();
// 实例化为 string 类型
Box<std::string> stringBox("Hello Template!");
stringBox.show();
}
3. 多参数类模板
3.1 多个类型参数
cpp
template<typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(const T1& f, const T2& s) : first(f), second(s) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
void setFirst(const T1& f) { first = f; }
void setSecond(const T2& s) { second = s; }
void display() const {
std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
}
};
void multiParamDemo() {
std::cout << "\n=== 多参数类模板 ===" << std::endl;
Pair<int, std::string> student(1001, "Alice");
student.display();
Pair<std::string, double> product("Apple", 5.99);
product.display();
Pair<int, Pair<int, std::string>> nested(1, Pair<int, std::string>(2, "Nested"));
nested.display();
}
3.2 非类型模板参数
cpp
template<typename T, int Size>
class FixedArray {
private:
T data[Size];
public:
FixedArray() {
for (int i = 0; i < Size; ++i) {
data[i] = T(); // 默认值
}
}
T& operator[](int index) {
if (index < 0 || index >= Size) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
const T& operator[](int index) const {
if (index < 0 || index >= Size) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
int getSize() const { return Size; }
void print() const {
std::cout << "FixedArray[" << Size << "]: ";
for (int i = 0; i < Size; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};
void nonTypeParamDemo() {
std::cout << "\n=== 非类型模板参数 ===" << std::endl;
FixedArray<int, 5> intArray;
intArray[0] = 10;
intArray[1] = 20;
intArray.print();
FixedArray<double, 3> doubleArray;
doubleArray[0] = 1.1;
doubleArray[1] = 2.2;
doubleArray[2] = 3.3;
doubleArray.print();
}
4. 类模板的特化
4.1 完全特化
cpp
#include <cstring>
// 主模板
template<typename T>
class Comparator {
public:
static bool equal(const T& a, const T& b) {
return a == b;
}
};
// 完全特化 - 针对 const char* 类型
template<>
class Comparator<const char*> {
public:
static bool equal(const char* a, const char* b) {
return strcmp(a, b) == 0;
}
};
void specializationDemo() {
std::cout << "\n=== 类模板特化 ===" << std::endl;
// 使用主模板
std::cout << "int equal: " << Comparator<int>::equal(10, 10) << std::endl;
std::cout << "string equal: " << Comparator<std::string>::equal("hello", "hello") << std::endl;
// 使用特化版本
std::cout << "C-string equal: " << Comparator<const char*>::equal("hello", "hello") << std::endl;
std::cout << "C-string not equal: " << Comparator<const char*>::equal("hello", "world") << std::endl;
}
4.2 部分特化
cpp
// 主模板
template<typename T1, typename T2>
class MyClass {
public:
void show() {
std::cout << "Primary template" << std::endl;
}
};
// 部分特化 - 两个类型相同
template<typename T>
class MyClass<T, T> {
public:
void show() {
std::cout << "Partial specialization: T, T" << std::endl;
}
};
// 部分特化 - 第二个类型为 int
template<typename T>
class MyClass<T, int> {
public:
void show() {
std::cout << "Partial specialization: T, int" << std::endl;
}
};
// 部分特化 - 两个类型都是指针
template<typename T1, typename T2>
class MyClass<T1*, T2*> {
public:
void show() {
std::cout << "Partial specialization: T1*, T2*" << std::endl;
}
};
void partialSpecializationDemo() {
std::cout << "\n=== 部分特化 ===" << std::endl;
MyClass<int, double> obj1; // 主模板
obj1.show();
MyClass<int, int> obj2; // 部分特化:T, T
obj2.show();
MyClass<double, int> obj3; // 部分特化:T, int
obj3.show();
MyClass<int*, double*> obj4; // 部分特化:T1*, T2*
obj4.show();
}
5. 实际应用示例
5.1 智能指针模板
cpp
template<typename T>
class SimpleUniquePtr {
private:
T* ptr;
public:
// 构造函数
explicit SimpleUniquePtr(T* p = nullptr) : ptr(p) {}
// 禁止拷贝
SimpleUniquePtr(const SimpleUniquePtr&) = delete;
SimpleUniquePtr& operator=(const SimpleUniquePtr&) = delete;
// 移动构造
SimpleUniquePtr(SimpleUniquePtr&& other) noexcept : ptr(other.ptr) {
other.ptr = nullptr;
}
// 移动赋值
SimpleUniquePtr& operator=(SimpleUniquePtr&& other) noexcept {
if (this != &other) {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
// 析构函数
~SimpleUniquePtr() {
delete ptr;
}
// 操作符重载
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }
T* get() const { return ptr; }
// 释放所有权
T* release() {
T* temp = ptr;
ptr = nullptr;
return temp;
}
// 重置指针
void reset(T* p = nullptr) {
delete ptr;
ptr = p;
}
// 布尔转换
explicit operator bool() const { return ptr != nullptr; }
};
void smartPointerDemo() {
std::cout << "\n=== 智能指针模板 ===" << std::endl;
SimpleUniquePtr<int> ptr1(new int(42));
std::cout << "Value: " << *ptr1 << std::endl;
SimpleUniquePtr<std::string> ptr2(new std::string("Hello"));
std::cout << "Length: " << ptr2->length() << std::endl;
// 移动语义
SimpleUniquePtr<int> ptr3 = std::move(ptr1);
if (!ptr1) {
std::cout << "ptr1 is now empty after move" << std::endl;
}
std::cout << "ptr3 value: " << *ptr3 << std::endl;
}
5.2 容器模板
cpp
template<typename T>
class DynamicArray {
private:
T* data;
size_t capacity;
size_t size;
void resize() {
capacity = capacity == 0 ? 1 : capacity * 2;
T* newData = new T[capacity];
for (size_t i = 0; i < size; ++i) {
newData[i] = data[i];
}
delete[] data;
data = newData;
}
public:
DynamicArray() : data(nullptr), capacity(0), size(0) {}
~DynamicArray() {
delete[] data;
}
void pushBack(const T& value) {
if (size >= capacity) {
resize();
}
data[size++] = value;
}
T& operator[](size_t index) {
if (index >= size) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
const T& operator[](size_t index) const {
if (index >= size) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
size_t getSize() const { return size; }
size_t getCapacity() const { return capacity; }
void print() const {
std::cout << "Array (size=" << size << ", capacity=" << capacity << "): ";
for (size_t i = 0; i < size; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};
void containerDemo() {
std::cout << "\n=== 容器模板 ===" << std::endl;
DynamicArray<int> intArray;
for (int i = 0; i < 10; ++i) {
intArray.pushBack(i * i);
}
intArray.print();
DynamicArray<std::string> strArray;
strArray.pushBack("Hello");
strArray.pushBack("World");
strArray.pushBack("Template");
strArray.print();
}
6. 类模板的继承
6.1 模板继承模板
cpp
template<typename T>
class Base {
protected:
T value;
public:
Base(const T& v) : value(v) {}
virtual void show() {
std::cout << "Base value: " << value << std::endl;
}
};
template<typename T>
class Derived : public Base<T> {
private:
T extraValue;
public:
Derived(const T& v1, const T& v2) : Base<T>(v1), extraValue(v2) {}
void show() override {
std::cout << "Base value: " << this->value << ", Extra: " << extraValue << std::endl;
}
};
void inheritanceDemo() {
std::cout << "\n=== 模板继承 ===" << std::endl;
Derived<int> derived1(10, 20);
derived1.show();
Derived<std::string> derived2("Hello", "World");
derived2.show();
}
7. 友元和静态成员
7.1 模板中的静态成员
cpp
template<typename T>
class Counter {
private:
T value;
static int count; // 静态成员
public:
Counter(const T& v) : value(v) {
count++;
}
~Counter() {
count--;
}
static int getCount() {
return count;
}
void show() const {
std::cout << "Value: " << value << ", Total instances: " << count << std::endl;
}
};
// 静态成员定义(每个实例化都有自己的一份)
template<typename T>
int Counter<T>::count = 0;
void staticMemberDemo() {
std::cout << "\n=== 模板静态成员 ===" << std::endl;
Counter<int> c1(10);
c1.show();
Counter<int> c2(20);
c2.show();
Counter<double> c3(3.14);
c3.show();
Counter<std::string> c4("Hello");
c4.show();
std::cout << "Int counters: " << Counter<int>::getCount() << std::endl;
std::cout << "Double counters: " << Counter<double>::getCount() << std::endl;
std::cout << "String counters: " << Counter<std::string>::getCount() << std::endl;
}
8. 类型推导和 CTAD(C++17)
C++17 类模板参数推导
cpp
template<typename T>
class Point {
private:
T x, y;
public:
Point(T x, T y) : x(x), y(y) {}
void show() const {
std::cout << "Point(" << x << ", " << y << ")" << std::endl;
}
};
// 推导指引
template<typename T>
Point(T, T) -> Point<T>;
void ctadDemo() {
std::cout << "\n=== CTAD (C++17) ===" << std::endl;
// C++17 之前需要指定类型
Point<int> p1(10, 20);
p1.show();
// C++17 可以自动推导类型
Point p2(3.14, 2.71); // 推导为 Point<double>
p2.show();
Point p3("hello", "world"); // 推导为 Point<const char*>
p3.show();
}
9. 完整测试程序
cpp
int main() {
std::cout << "=== 类模板详解 ===" << std::endl;
basicTemplateDemo(); // 基本模板
multiParamDemo(); // 多参数模板
nonTypeParamDemo(); // 非类型参数
specializationDemo(); // 完全特化
partialSpecializationDemo(); // 部分特化
smartPointerDemo(); // 智能指针
containerDemo(); // 容器模板
inheritanceDemo(); // 模板继承
staticMemberDemo(); // 静态成员
ctadDemo(); // CTAD
std::cout << "\n=== 所有演示完成 ===" << std::endl;
return 0;
}
10. 总结
类模板的核心概念:
-
🎯 泛型编程:编写与数据类型无关的代码
-
🎯 代码复用:同一套逻辑适用于多种类型
-
🎯 类型安全:编译时类型检查
-
🎯 性能优化:没有运行时开销
关键特性:
| 特性 | 说明 | 示例 |
|---|---|---|
| 类型参数 | template<typename T> |
支持任意类型 |
| 多参数 | template<T1, T2> |
多个类型参数 |
| 非类型参数 | template<int Size> |
值作为参数 |
| 特化 | 针对特定类型的优化 | 完全特化、部分特化 |
| 继承 | 模板类可以继承 | 代码复用 |
| 静态成员 | 每个实例化有自己的静态成员 | 类型特定的计数 |
最佳实践:
-
✅ 使用有意义的模板参数名
-
✅ 提供充分的异常安全保证
-
✅ 考虑特化以优化特定类型
-
✅ 使用概念(C++20)约束模板参数
-
✅ 利用 CTAD 简化代码
掌握了类模板,你就掌握了 C++ 泛型编程的核心能力!