C++笔记(面向对象)类模板

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> 值作为参数
特化 针对特定类型的优化 完全特化、部分特化
继承 模板类可以继承 代码复用
静态成员 每个实例化有自己的静态成员 类型特定的计数

最佳实践:

  1. ✅ 使用有意义的模板参数名

  2. ✅ 提供充分的异常安全保证

  3. ✅ 考虑特化以优化特定类型

  4. ✅ 使用概念(C++20)约束模板参数

  5. ✅ 利用 CTAD 简化代码

掌握了类模板,你就掌握了 C++ 泛型编程的核心能力!

相关推荐
JJJJ_iii4 小时前
【机器学习10】项目生命周期、偏斜类别评估、决策树
人工智能·python·深度学习·算法·决策树·机器学习
fie88895 小时前
基于MATLAB的LBFGS优化算法实现
算法·matlab
天选之女wow5 小时前
【代码随想录算法训练营——Day50(Day49周日休息)】图论——98.所有可达路径
算法·图论
刀法自然5 小时前
栈实现表达式求值
数据结构·算法·图论
我搞slam5 小时前
有效的括号--leetcode
linux·算法·leetcode
ゞ 正在缓冲99%…7 小时前
leetcode1312.让字符串成为回文串的最少插入次数
数据结构·算法·leetcode·动态规划·记忆化搜索
七夜zippoe7 小时前
Rust `std::iter` 深度解析:`Iterator` Trait、适配器与性能
开发语言·算法·rust
寂静山林7 小时前
UVa 1464 Traffic Real Time Query System
算法
laocooon5238578867 小时前
寻找使a×b=c成立的最小进制数(2-16进制)
数据结构·算法