C++学习 day13

发布于 17 天前  91 次阅读


Day 13:类模板与 vector

本节代码位置:

2-代码/day13-类模板/71-类模板使用示例.cpp
2-代码/day13-类模板/72-vector使用示例.cpp
2-代码/day13-类模板/list.hpp
2-代码/day13-类模板/stack.hpp
2-代码/day13-类模板/myalgo.hpp

1、类模板

类模板让一个类可以处理不同的数据类型。课程中的链表和栈不再只能保存某一种元素,而是通过类型参数决定元素类型。

template <typename Type>
class List
{
    // 节点数据、push_back、迭代器等都使用 Type
};

List<int> l1;
List<string> l2;

List<int>List<string> 是同一个模板生成的两个具体类型,它们的操作逻辑相同,保存的数据类型不同。

2、模板栈与别名模板

MyStack 在内部复用了 List<Type>

template <typename Type>
class MyStack
{
public:
    void push(Type x);
    void pop();
    Type top() const;

private:
    List<Type> _list;
    int _capacity;
};

栈的容量已满时会抛出 std::overflow_error。别名模板可以给类型换一个更贴近用途的名字:

template <typename Type>
using LinkStack = MyStack<Type>;

3、模板实现为什么通常放在头文件

普通函数先编译成固定目标代码;模板则要等到使用 List<int>List<string> 时,编译器才根据实际类型生成代码。

模板的声明和实现通常都放在 .hpp 头文件中。
如果把模板实现单独放进 .cpp,其他源文件实例化模板时看不到实现,通常会产生链接错误。

4、迭代器与通用算法

myfind 不绑定 Listvectorstring。它只要求传入的迭代器支持比较、递增和解引用。

template <typename Iterator, typename T>
Iterator myfind(Iterator first, Iterator last, T x)
{
    for (; first != last; ++first)
    {
        if (*first == x)
            return first;
    }
    return last;
}
auto it = myfind(l1.begin(), l1.end(), 300);
if (it != l1.end())
{
    *it = 999;
}
begin() 指向第一个元素。
end() 指向尾后位置,不是最后一个元素。
查找成功返回目标元素的位置;失败返回 end()。
迭代器解引用得到元素本身,因此可以读取或修改元素。

5、vector 动态数组

std::vector 是标准库的动态数组,元素连续存储,支持下标访问。

vector<int> a;                       // 空 vector
vector<int> a2 = {1, 2, 3, 4, 5};     // 列表初始化
vector<int> a3(a2.begin(), a2.end()); // 迭代器区间构造

int arr[5] = {1, 2, 3, 4, 5};
vector<int> a4(arr, arr + 3);         // 原始数组区间构造

6、圆括号与大括号

vector<int> a6(10); // 创建 10 个默认初始化元素
vector<int> a7{10}; // 创建 1 个元素,值为 10
() 常用于“数量”或构造参数。
{} 优先表示列表初始化。
vector<int> v(10) 与 vector<int> v{10} 的含义完全不同。

7、vector 常用操作

a.push_back(1); // 尾部添加
 a.pop_back();  // 删除最后一个元素
a[0] = 100;     // 下标修改

auto it = find(a.begin(), a.end(), 6);
auto it2 = find_if(a.begin(), a.end(),
                   [](int x) { return x < 100; });

find 按值查找;find_if 根据谓词查找,示例中的 lambda 表达式表示“查找小于 100 的元素”。

8、size 与 capacity

size():当前实际元素个数。
capacity():已经分配、最多可容纳的元素数量。

push_back() 发现容量不足时,vector 会重新分配一段更大的连续空间,再迁移旧元素。因此扩容后,之前保存的迭代器、指针和引用可能失效。

9、Day13 总结

1. 类模板让容器和数据结构支持多种元素类型。
2. 使用时写成 类名<实际类型>,例如 List<int>。
3. 模板实现通常放在头文件。
4. 迭代器把容器和算法连接起来。
5. vector 是连续存储的动态数组,支持随机访问。
6. vector 的 () 与 {} 初始化含义不同。
7. vector 扩容可能使旧迭代器、指针和引用失效。

一句话记忆:模板让类和算法按类型复用;迭代器让算法不绑定具体容器;vector 是可自动扩容的连续动态数组。


"When faced with uncertainty, ask the spring breeze."