de风——【从零开始学C++】(六):模板初阶

📚 系列文章导航

【从零开始学 C++】专题正在持续更新中🔥

  • 第一篇:C++ 入门 ------ 从 C 到 C++ 的跨越

  • 第二篇:类和对象 (上)------ 面向对象的开端

  • 第三篇:类和对象 (中)------ 构造析构与运算符重载

  • 第四篇:类和对象 (下)------ 静态成员与友元

  • 第五篇:C++ 内存管理 ------new 与 delete 的奥秘

  • 第六篇:模板初阶 ------ 让你的代码 "万能" 起来 👈 你在这里

  • 第七篇:STL 简介和入门(敬请期待)

【从零开始学 C++】专题

https://blog.csdn.net/xiao_running/category_13158015.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=13158015&sharerefer=PC&sharesource=Xiao_running&sharefrom=from_linkhttps://blog.csdn.net/xiao_running/category_13158015.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=13158015&sharerefer=PC&sharesource=Xiao_running&sharefrom=from_link

目录

[📚 系列文章导航](#📚 系列文章导航)

(一)泛型编程

[1. 基础概念解释](#1. 基础概念解释)

[2. 代码示例](#2. 代码示例)

(二)函数模板

[1. 函数模板的概念](#1. 函数模板的概念)

代码示例

[2. 函数模板的格式](#2. 函数模板的格式)

关键点说明:

代码示例

[3. 函数模板的原理](#3. 函数模板的原理)

代码示例

[4. 函数模板的实例化](#4. 函数模板的实例化)

代码示例

[5. 模板参数的匹配原则](#5. 模板参数的匹配原则)

代码示例

(三)类模板

[1. 类模板的定义格式](#1. 类模板的定义格式)

基础概念解释

代码示例

[2. 类模板的实例化](#2. 类模板的实例化)

基础概念解释

代码示例

[🎯 本篇总结](#🎯 本篇总结)

[📢 下一篇预告](#📢 下一篇预告)


哈喽各位小伙伴们大家好!我是你们的小小风吖,今天我们来学习 C++ 中又一个超级重要的概念 ------模板

不知道大家有没有过这种经历:写了一个交换函数,只能交换 int 类型;后来要交换 double,又得重写一遍;再后来要交换 char,又得再写一遍... 是不是觉得特别麻烦?

cpp 复制代码
void Swap(int& a, int& b) { int t = a; a = b; b = t; }
void Swap(double& a, double& b) { double t = a; a = b; b = t; }
void Swap(char& a, char& b) { char t = a; a = b; b = t; }
// ... 还有完没完啊!

今天学完模板,你就会发现:原来这些重复的代码,只需要写一遍就够了! 让我们一起进入泛型编程的世界吧~


(一)泛型编程

1. 基础概念解释

大白话时间:

想象一下,你是一个做月饼的师傅。如果做豆沙月饼要一套模具,做五仁月饼又要一套模具,做蛋黄莲蓉还要一套模具... 那你家里得堆多少模具啊?

但聪明的师傅会怎么做呢?------做一个通用的月饼模具,往里面填什么馅料,就出来什么口味的月饼! 这就是 "泛型" 的思想。

泛型编程 就是:编写与类型无关的通用代码。就像那个通用的月饼模具,我们写一个通用的 "代码模具",编译器会根据我们传入的 "材料"(数据类型),自动生成对应类型的代码。

模板就是 C++ 中实现泛型编程的基础工具。模板分为两大类:

  • 函数模板:针对函数的通用模具

  • 类模板:针对类的通用模具

💡 实用小贴士:模板是 STL(标准模板库)的基础,我们后面要学的 vector、list、map 这些容器,全都是用模板实现的!学好模板,STL 就成功了一半!


2. 代码示例

【示例 1:没有模板时的痛苦 ------ 函数重载】

这个例子展示:没有模板的情况下,要实现不同类型的交换,需要写 N 多重复代码。

cpp 复制代码
#include <iostream>
using namespace std;

// 交换int类型
void Swap(int& left, int& right) {
    int temp = left;
    left = right;
    right = temp;
    cout << "调用了int版本的Swap" << endl;
}

// 交换double类型
void Swap(double& left, double& right) {
    double temp = left;
    left = right;
    right = temp;
    cout << "调用了double版本的Swap" << endl;
}

// 交换char类型
void Swap(char& left, char& right) {
    char temp = left;
    left = right;
    right = temp;
    cout << "调用了char版本的Swap" << endl;
}

int main() {
    int a = 10, b = 20;
    Swap(a, b);
    cout << "a = " << a << ", b = " << b << endl << endl;
    
    double c = 1.1, d = 2.2;
    Swap(c, d);
    cout << "c = " << c << ", d = " << d << endl << endl;
    
    char e = 'x', f = 'y';
    Swap(e, f);
    cout << "e = " << e << ", f = " << f << endl;
    
    return 0;
}

运行结果:

cpp 复制代码
调用了int版本的Swap
a = 20, b = 10

调用了double版本的Swap
c = 2.2, d = 1.1

调用了char版本的Swap
e = y, f = x

⚠️ 问题来了:如果我明天要交换 float 类型,后天要交换 long 类型,大后天还要交换自定义类型... 难道我要一直写下去吗?这就是模板要解决的问题!


(二)函数模板

1. 函数模板的概念

大白话时间:

函数模板就是一个 "函数模具"。你告诉编译器:"我这里有一个模具,你帮我按照这个模具,根据我给的类型生成具体的函数。"

就像活字印刷术一样:以前雕版印刷,每一页要刻一个版;活字印刷就厉害了,你要什么字,就把对应的活字拿出来组合。函数模板就是那个 "活字" 的思想。

官方一点的定义:函数模板代表了一个函数家族,它和类型无关,在使用时会根据你传入的实参类型,自动产生对应类型的函数版本。


代码示例

【示例 2:函数模板初体验 ------ 万能 Swap】

这个例子展示:用函数模板,只写一遍代码,就能支持所有类型的交换!

cpp 复制代码
#include <iostream>
using namespace std;

// 这就是函数模板!T是一个"虚拟类型"
template<typename T> //这里也可以用<class T> 用class和typename都可以
void Swap(T& left, T& right) {
    T temp = left;
    left = right;
    right = temp;
    cout << "调用了模板生成的Swap" << endl;
}

int main() {
    // 交换int类型
    int a = 10, b = 20;
    Swap(a, b);  // 编译器自动生成int版本的Swap
    cout << "int交换: a = " << a << ", b = " << b << endl << endl;
    
    // 交换double类型
    double c = 1.1, d = 2.2;
    Swap(c, d);  // 编译器自动生成double版本的Swap
    cout << "double交换: c = " << c << ", d = " << d << endl << endl;
    
    // 交换char类型
    char e = 'x', f = 'y';
    Swap(e, f);  // 编译器自动生成char版本的Swap
    cout << "char交换: e = " << e << ", f = " << f << endl;
    
    return 0;
}

运行结果:

cpp 复制代码
调用了模板生成的Swap
int交换: a = 20, b = 10

调用了模板生成的Swap
double交换: c = 2.2, d = 1.1

调用了模板生成的Swap
char交换: e = y, f = x

🎉 太神奇了! 我们只写了一遍代码,居然支持了三种类型!而且你还可以用它交换 float、long、甚至你自己定义的类型!这就是模板的威力!


2. 函数模板的格式

大白话时间:

函数模板的格式很简单,记住这个公式就行:

cpp 复制代码
template<typename T1, typename T2, ...>
返回值类型 函数名(参数列表) {
    // 函数体,里面可以用T1、T2这些虚拟类型
}
关键点说明:
  1. template:告诉编译器 "我要定义模板了"

  2. <typename T>:尖括号里是模板参数列表,typename是关键字,T是我们给虚拟类型起的名字(可以随便起,叫 T、K、V 都行,习惯上用大写字母)

  3. 注意typename也可以写成class,效果完全一样!但是不能写成 struct哦!

💡 新手避坑 :模板参数列表里的每个类型前面,都要写 typename!比如template<typename T1, T2>是错的,应该是template<typename T1, typename T2>


代码示例

【示例 3:多模板参数的函数模板】

这个例子展示:模板可以有多个类型参数,实现更灵活的通用函数。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 两个模板参数:T1和T2可以是不同的类型
template<typename T1, typename T2>
void Print(const T1& t1, const T2& t2) {
    cout << "第一个参数:" << t1 << ",类型是:" << typeid(T1).name() << endl;
    cout << "第二个参数:" << t2 << ",类型是:" << typeid(T2).name() << endl;
    cout << "------------------------" << endl;
}

int main() {
    // int和double组合
    Print(10, 3.14);
    
    // char和string组合
    Print('A', string("Hello C++"));
    
    // string和bool组合
    Print(string("模板真好玩"), true);
    
    return 0;
}

运行结果:

cpp 复制代码
第一个参数:10,类型是:i
第二个参数:3.14,类型是:d
------------------------
第一个参数:A,类型是:c
第二个参数:Hello C++,类型是:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
------------------------
第一个参数:模板真好玩,类型是:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
第二个参数:1,类型是:b
------------------------

💡 小知识typeid(xxx).name()可以查看类型的名字,虽然输出的名字有点奇怪(比如 i 就是 int,d 就是 double),但调试的时候很好用!


3. 函数模板的原理

大白话时间:

很多新手会问:"模板函数是怎么做到支持所有类型的?难道它真的是一个万能函数?"

答案是:NO! 模板本身不是 一个真正的函数!它只是一个模具

真正的过程是这样的:

  1. 编译阶段 :编译器看到你调用Swap(a, b),发现 a 和 b 是 int 类型

  2. 编译器就拿着你的模板模具,把 T 全部替换成 int,生成一个真正的 int 版本的 Swap 函数

  3. 然后你调用的其实是这个生成出来的 int 版本函数

  4. 同理,调用Swap(c, d)时,c 和 d 是 double,编译器又生成一个 double 版本的 Swap 函数

所以说:模板是把本来应该我们做的重复劳动,交给编译器去做了! 我们写一遍,编译器帮我们生成 N 遍。

💡 重要理解 :模板是在编译期处理的,不是运行期!生成的代码里,int 版本和 double 版本是两个完全不同的函数,就像你自己写的重载函数一样。


代码示例

【示例 4:验证模板原理 ------ 查看地址】

这个例子证明:不同类型的模板函数,地址是不一样的,说明它们是不同的函数!

cpp 复制代码
#include <iostream>
using namespace std;

template<typename T>
T Add(const T& a, const T& b) {
    return a + b;
}

int main() {
    int a = 10, b = 20;
    double c = 1.1, d = 2.2;
    
    // 调用Add<int>
    cout << "Add(a, b) = " << Add(a, b) << endl;
    
    // 调用Add<double>
    cout << "Add(c, d) = " << Add(c, d) << endl;
    
    // 打印函数地址,看看是不是同一个函数
    cout << endl;
    cout << "Add<int>的函数地址:" << (void*)Add<int> << endl;
    cout << "Add<double>的函数地址:" << (void*)Add<double> << endl;
    
    if ((void*)Add<int> == (void*)Add<double>) {
        cout << "两个函数地址相同,是同一个函数" << endl;
    } else {
        cout << "两个函数地址不同,是不同的函数!" << endl;
        cout << "这说明编译器根据模板生成了两份不同的代码!" << endl;
    }
    
    return 0;
}

运行结果:

cpp 复制代码
Add(a, b) = 30
Add(c, d) = 3.3

Add<int>的函数地址:0x401550
Add<double>的函数地址:0x401570
两个函数地址不同,是不同的函数!
这说明编译器根据模板生成了两份不同的代码!

🎉 完美验证! 两个函数地址不一样,说明它们确实是两个独立的函数!这就是模板的工作原理。


4. 函数模板的实例化

大白话时间:

"实例化" 这个词听起来很高大上,其实就是:用模板模具生成真正函数的过程

就像你用月饼模具做月饼的过程,模具本身不是月饼,把模具压下去,出来的那个东西才是真正的月饼 ------ 这个 "压下去做出月饼" 的过程,就是实例化。

模板实例化分两种:

  1. 隐式实例化:编译器自动帮你推导出类型是什么,你什么都不用管

  2. 显式实例化:你手动告诉编译器,我就要用这个类型!

💡 新手避坑:隐式实例化时,编译器不会做类型转换!比如你传一个 int 和一个 double 给同一个 T,编译器会报错说 "类型矛盾",而不是自动把 int 转成 double!这时候就要用显式实例化。


代码示例

【示例 5:隐式实例化 vs 显式实例化】

这个例子展示两种实例化方式,以及什么时候必须用显式实例化。

cpp 复制代码
#include <iostream>
using namespace std;

template<class T>  // 这里用class代替typename,效果一样
T Add(const T& left, const T& right) {
    return left + right;
}

int main() {
    int a = 10;
    double b = 20.5;
    
    // ========== 1. 隐式实例化:编译器自动推演类型 ==========
    cout << "Add(a, 20) = " << Add(a, 20) << endl;  // T推演成int
    cout << "Add(1.5, b) = " << Add(1.5, b) << endl; // T推演成double
    
    // ========== 2. 下面这行会报错! ==========
    // Add(a, b);  
    // 错误原因:a是int,b是double,编译器不知道T该是什么
    // 编译器不会做类型转换!
    
    // ========== 3. 解决方法1:强制类型转换 ==========
    cout << "Add(a, (int)b) = " << Add(a, (int)b) << endl;
    
    // ========== 4. 解决方法2:显式实例化!手动指定类型 ==========
    cout << "Add<int>(a, b) = " << Add<int>(a, b) << endl;     // 都转成int
    cout << "Add<double>(a, b) = " << Add<double>(a, b) << endl; // 都转成double
    
    cout << endl << "显式实例化成功!手动指定T的类型就是这么简单!" << endl;
    
    return 0;
}

运行结果:

cpp 复制代码
Add(a, 20) = 30
Add(1.5, b) = 22
Add(a, (int)b) = 30
Add<int>(a, b) = 30
Add<double>(a, b) = 30.5

显式实例化成功!手动指定T的类型就是这么简单!

💡 总结 :当编译器无法自动推演类型,或者推演的结果不符合你的预期时,就用<类型>手动指定!但是就结果而言,我们强行将double类型转化为int类型时,会导致结果出现偏差,所以我们在使用显示类型转化时,要就具体情况来转换


5. 模板参数的匹配原则

大白话时间:

现在问题来了:如果我既有一个普通的 Add 函数(专门处理 int),又有一个 Add 模板,那我调用 Add (1, 2) 时,编译器会调用哪一个?

这就涉及到模板的匹配原则了,记住三条铁律:

  1. 普通函数优先:如果有现成的普通函数刚好匹配,就用普通函数,不用模板生成

  2. 更好匹配优先:如果模板能生成比普通函数更匹配的版本,那就用模板

  3. 模板不做自动类型转换:普通函数可以做隐式类型转换,但模板函数不会

💡 实用技巧 :如果你就是想调用模板版本,哪怕有普通函数,那就用显式实例化:Add<int>(1, 2),这样一定会调用模板!


代码示例

【示例 6:模板与普通函数的匹配规则】

这个例子完整演示三条匹配原则,超级重要!

cpp 复制代码
#include <iostream>
using namespace std;

// 普通函数:专门处理int的加法
int Add(int left, int right) {
    cout << "【调用了普通函数Add(int, int)】" << endl;
    return left + right;
}

// 函数模板:通用加法
template<class T>
T Add(T left, T right) {
    cout << "【调用了模板Add<T>】,T的类型是:" << typeid(T).name() << endl;
    return left + right;
}

// 两个参数可以是不同类型的模板
template<class T1, class T2>
T1 Add(T1 left, T2 right) {
    cout << "【调用了模板Add<T1, T2>】" << endl;
    return left + right;
}

int main() {
    cout << "===== 测试1:两个int参数 =====" << endl;
    Add(1, 2);  // 刚好匹配普通函数,优先调用普通函数
    
    cout << endl << "===== 测试2:显式指定用模板 =====" << endl;
    Add<int>(1, 2);  // 强制调用模板版本
    
    cout << endl << "===== 测试3:两个double参数 =====" << endl;
    Add(1.1, 2.2);  // 普通函数不匹配,用模板生成double版本
    
    cout << endl << "===== 测试4:一个int一个double =====" << endl;
    Add(1, 2.2);  // 普通函数需要把2.2转成int,而模板可以生成更匹配的版本
    // 所以这里会调用模板!  
    return 0;
}

运行结果:

cpp 复制代码
===== 测试1:两个int参数 =====
【调用了普通函数Add(int, int)】

===== 测试2:显式指定用模板 =====
【调用了模板Add<T>】,T的类型是:i

===== 测试3:两个double参数 =====
【调用了模板Add<T>】,T的类型是:d

===== 测试4:一个int一个double =====
【调用了模板Add<T1, T2>】

**===== 总结匹配原则 =====

  1. 有完全匹配的普通函数,优先用普通函数
  2. 模板能生成更好的匹配,就用模板
  3. 显式实例化一定调用模板**

🎉 **完美!**这三条原则记住了,模板匹配的问题就难不倒你了!


(三)类模板

1. 类模板的定义格式

基础概念解释

大白话时间:

函数模板是针对函数的模具,那类模板就是针对类的模具啦!

想想我们之前学的栈:如果我要一个存 int 的栈,要写一个 Stack 类;要一个存 double 的栈,又要写一个;要一个存 string 的栈,还要写一个... 是不是又回到了之前的问题?

类模板就是解决这个的:写一个通用的 Stack 类模板,要存什么类型,就把类型告诉编译器,编译器帮你生成对应类型的栈类。

类模板的格式:

cpp 复制代码
template<class T1, class T2, ...>
class 类名 {
    // 类里面可以用T1、T2这些类型
};

⚠️ 超级重要的坑 :类模板的成员函数如果要在类外面定义,必须加上模板参数!而且类模板不建议声明和定义分离到.h 和.cpp 两个文件,会出现链接错误!这个坑我们后面进阶篇会详细讲。


代码示例

【示例 7:实现一个通用的栈类模板】

这是一个完整可运行的栈类模板,包含了常用的接口。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 通用的栈类模板
template<class T>
class Stack {
public:
    // 构造函数:默认容量是4
    Stack(size_t capacity = 4)
        : _array(new T[capacity])
        , _capacity(capacity)
        , _size(0)
    {}
    
    // 析构函数
    ~Stack() {
        delete[] _array;
        _array = nullptr;
        _capacity = _size = 0;
    }
    
    // 入栈
    void Push(const T& data);
    
    // 出栈
    void Pop() {
        if (_size > 0) {
            _size--;
        }
    }
    
    // 获取栈顶元素
    T& Top() {
        return _array[_size - 1];
    }
    
    // 获取栈的大小
    size_t Size() {
        return _size;
    }
    
    // 判断是否为空
    bool Empty() {
        return _size == 0;
    }
    
private:
    T* _array;       // 用T类型的数组存储数据
    size_t _capacity;
    size_t _size;
};

// ⚠️ 注意:类模板的成员函数在类外定义时,必须加上模板参数!
template<class T>
void Stack<T>::Push(const T& data) {
    // 这里简化处理,不写扩容逻辑了
    if (_size < _capacity) {
        _array[_size] = data;
        _size++;
    }
}

int main() {
    cout << "========== int类型的栈 ==========" << endl;
    Stack<int> st1;  // 存int的栈
    st1.Push(1);
    st1.Push(2);
    st1.Push(3);
    
    while (!st1.Empty()) {
        cout << st1.Top() << " ";
        st1.Pop();
    }
    cout << endl << endl;
    
    cout << "========== double类型的栈 ==========" << endl;
    Stack<double> st2;  // 存double的栈
    st2.Push(1.1);
    st2.Push(2.2);
    st2.Push(3.3);
    
    while (!st2.Empty()) {
        cout << st2.Top() << " ";
        st2.Pop();
    }
    cout << endl << endl;
    
    cout << "========== string类型的栈 ==========" << endl;
    Stack<string> st3;  // 存string的栈
    st3.Push("Hello");
    st3.Push("C++");
    st3.Push("模板");
    
    while (!st3.Empty()) {
        cout << st3.Top() << " ";
        st3.Pop();
    }
    cout << endl;
    
    return 0;
}

运行结果:

cpp 复制代码
========== int类型的栈 ==========
3 2 1 

========== double类型的栈 ==========
3.3 2.2 1.1 

========== string类型的栈 ==========
模板 C++ Hello

🎉 太牛了! 一个类模板,支持 int、double、string 三种类型!而且你还可以用它存你自己定义的任何类型!


2. 类模板的实例化

基础概念解释

大白话时间:

类模板的实例化和函数模板有点不一样:

  • 函数模板可以隐式实例化(编译器自动推类型)

  • 类模板必须显式实例化!你必须手动告诉编译器类型是什么!

也就是说,你不能这样写:

cpp 复制代码
Stack st;  // ❌ 错误!类模板不能隐式实例化

必须这样写:

cpp 复制代码
Stack<int> st;  // ✅ 正确!显式指定类型

还有一个重要概念:Stack类模板名 ,不是真正的类;Stack<int>才是真正的类型

就像:"月饼模具" 不是月饼,"用模具做出来的豆沙月饼" 才是真正的月饼!


代码示例

【示例 8:类模板实例化的注意事项】

这个例子展示类模板实例化的各种细节和注意点。

cpp 复制代码
#include <iostream>
#include <typeinfo>
using namespace std;

template<class T>
class MyClass {
public:
    MyClass() {
        cout << "MyClass被实例化了,T的类型是:" << typeid(T).name() << endl;
    }
    void Print() {
        cout << "这是一个MyClass对象" << endl;
    }
private:
    T _data;
};

int main() {
    cout << "===== 类模板必须显式实例化! =====" << endl;
    
    // MyClass c;  // ❌ 编译错误!类模板不能隐式实例化
    
    MyClass<int> c1;       // ✅ int类型
    MyClass<double> c2;    // ✅ double类型
    MyClass<char> c3;      // ✅ char类型
    
    cout << endl << "===== 验证:不同实例化是不同类型 =====" << endl;
    
    cout << "MyClass<int>的类型信息:" << typeid(MyClass<int>).name() << endl;
    cout << "MyClass<double>的类型信息:" << typeid(MyClass<double>).name() << endl;
    
    if (typeid(MyClass<int>) == typeid(MyClass<double>)) {
        cout << "它们是同一个类型" << endl;
    } else {
        cout << "它们是完全不同的类型!" << endl;
        cout << "记住:MyClass是模板名,MyClass<int>才是真正的类型!" << endl;
    }
    
    cout << endl << "===== 类模板也可以有多个模板参数 =====" << endl;
    cout << "比如我们后面要学的map:map<string, int>" << endl;
    cout << "第一个参数是key的类型,第二个参数是value的类型" << endl;
    
    return 0;
}

运行结果:

cpp 复制代码
===== 类模板必须显式实例化! =====
MyClass被实例化了,T的类型是:i
MyClass被实例化了,T的类型是:d
MyClass被实例化了,T的类型是:c

===== 验证:不同实例化是不同类型 =====
MyClass<int>的类型信息:7MyClassIiE
MyClass<double>的类型信息:7MyClassIdE
它们是完全不同的类型!
记住:MyClass是模板名,MyClass<int>才是真正的类型!

===== 类模板也可以有多个模板参数 =====
比如我们后面要学的map:map<string, int>
第一个参数是key的类型,第二个参数是value的类型

🎯 本篇总结

恭喜你看到这里!模板初阶的内容我们就学完了,来回顾一下今天的重点:

|----------|----------------------|
| 知识点 | 核心要点 |
| 泛型编程 | 编写与类型无关的代码,模板是基础 |
| 函数模板 | 函数的模具,编译器根据类型生成具体函数 |
| 模板原理 | 编译期处理,不同类型生成不同函数 |
| 实例化 | 隐式(自动推)和显式(手动指定)两种 |
| 匹配原则 | 普通函数优先,更好匹配优先,显式强制模板 |
| 类模板 | 类的模具,必须显式实例化 |
| 重要区别 | 类模板名≠真正的类型,实例化后才是 |

💡 一句话总结:模板就是让编译器帮我们写重复代码的工具!


📢 下一篇预告

模板初阶到这里就先告一段落啦~

其实模板的知识点远不止这些,背后还有很多深层语法、细节坑点和进阶用法等着大家深挖,水真的特别深!

下一篇博客我们就正式告别模板基础,进军STL核心殿堂~

我会带大家从零入门STL容器、常用算法、迭代器底层逻辑,手把手拆解常用容器的用法、底层结构和实战场景,帮你轻松拿捏C++ STL,敬请期待吧!!


💬 如果这篇文章对你有帮助,别忘了点赞收藏关注三连哦!有任何问题欢迎在评论区留言,我会一一回复!

我是的小小的风,我们下一篇再见!👋

相关推荐
likerhood1 小时前
java的泛型(generics)详细讲解
java·开发语言
j_xxx404_1 小时前
力扣算法:用栈消消乐,巧解相邻重复与退格字符串
c++·算法·leetcode
知识分享小能手1 小时前
R语言入门学习教程,从入门到精通,R语言流程控制语句(5)
开发语言·学习·r语言
大龄码农-涵哥1 小时前
Java 调用 LLM 全解析:ChatGPT、Claude、通义千问一网打尽
java·开发语言·chatgpt
小新同学^O^1 小时前
简单学习 --> JVM
java·开发语言·python
郝学胜-神的一滴1 小时前
二叉树与递归:解锁高级数据结构的编程内功心法
开发语言·数据结构·c++·算法·面试
wjs20241 小时前
Julia 正则表达式
开发语言
基德爆肝c语言1 小时前
Qt:显示类控件
开发语言·qt·命令模式
潇湘散客1 小时前
CAX软件插件化设计实战:从框架到3D基础功能落地
c++·图形学·opengl