C++ | 类模板

一、类模板核心概念

类模板是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函数包装器

六、最佳实践指南

  1. 头文件组织
    类模板的定义和实现必须放在头文件中(编译器需要看到完整定义)

  2. 类型别名优化
    使用using简化复杂类型

    template <typename T>
    class Matrix {
    public:
        using Iterator = typename std::vector<T>::iterator;
        // ...
    };
  3. 友元函数处理
    声明友元需要特别注意模板参数

    template <typename U>
    friend std::ostream& operator<<(std::ostream&, const Matrix<U>&);
  4. 静态成员处理
    每个模板实例都有独立的静态成员

    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) { /*...*/ }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值