[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site-home-live-entry-setting":3,"site-header-contests":8,"site-header-camps":49,"study-material-detail-study-56":104},{"enabled":4,"title":5,"statusText":5,"buttonText":5,"campSlug":5,"stage":6,"classroomId":7,"hasClassroom":4},false,"",0,null,{"total":9,"list":10,"pageNum":44,"pageSize":45,"size":9,"startRow":44,"endRow":9,"pages":44,"prePage":6,"nextPage":6,"isFirstPage":46,"isLastPage":46,"hasPreviousPage":4,"hasNextPage":4,"navigatePages":47,"navigatepageNums":48,"navigateFirstPage":44,"navigateLastPage":44},3,[11,25,35],{"slug":12,"title":13,"logo":7,"liveUrl":14,"prize":15,"sponsor":16,"description":17,"organizer":18,"startTime":19,"endTime":20,"registrationDeadline":21,"status":22,"dashboardVisibility":23,"createdAt":24},"spring2026","2026春季启元人工智能大赛","https:\u002F\u002Fwww.bilibili.com\u002Fblackboard\u002Flive\u002Flive-activity-player.html?cid=1822703816&quality=0","200,000","麒麟软件有限公司","“2026春季启元人工智能大赛”是由启元实验室主办的面向全国人工智能领域开发者、科研人员及高校学生的权威赛事。大赛旨在促进与培养具备工程实践能力和创新能力的优秀人工智能领域开发者、推广国产软硬件技术与生态、助力国家人工智能产业高质量发展。\n各参赛选手需在规定的比赛周期内，依据赛事规则选定赛题并完成相应挑战，优胜者将共同角逐总额20万元的赛事奖金池，并且还将有机会获得实习和知名企业优质岗位内推资格。","启元实验室","2026-04-19 16:00:00","2026-07-13 16:00:00","2026-06-16 16:00:00","ongoing","private","2026-04-16 08:00:00",{"slug":26,"title":27,"logo":7,"liveUrl":14,"prize":28,"sponsor":7,"description":29,"organizer":18,"startTime":30,"endTime":31,"registrationDeadline":32,"status":33,"dashboardVisibility":23,"createdAt":34},"autumn2025","2025秋季启元人工智能大赛","150,000","“2025秋季启元人工智能大赛”是由启元实验室主办的面向全国人工智能领域开发者、科研人员及高校学生的权威赛事。大赛旨在促进与培养具备工程实践能力和创新能力的优秀人工智能领域开发者、推广国产软硬件技术与生态、助力国家人工智能产业高质量发展。","2025-11-08 08:00:00","2026-01-13 08:00:00","2025-12-30 08:00:00","ended","2025-11-03 08:00:00",{"slug":36,"title":37,"logo":7,"liveUrl":14,"prize":38,"sponsor":7,"description":39,"organizer":18,"startTime":40,"endTime":41,"registrationDeadline":42,"status":33,"dashboardVisibility":23,"createdAt":43},"summer2025","启元人工智能大赛(系统方向)","80,000","启元人工智能大赛由启元实验室主办，其中系统赛道基于启元实验室九源软件栈的相关开源项目，通过拉动开源社区力量，一方面促进国产智能计算生态的发展，另一方面也为人工智能系统方向的学生及从业者提供一个实践平台。","2025-07-08 08:00:00","2025-08-25 08:00:00","2025-07-22 08:00:00","2025-06-22 08:00:00",1,5,true,8,[44],{"total":45,"list":50,"pageNum":44,"pageSize":45,"size":45,"startRow":44,"endRow":45,"pages":44,"prePage":6,"nextPage":6,"isFirstPage":46,"isLastPage":46,"hasPreviousPage":4,"hasNextPage":4,"navigatePages":47,"navigatepageNums":103,"navigateFirstPage":44,"navigateLastPage":44},[51,62,73,84,94],{"id":52,"slug":53,"title":54,"logo":55,"publicLiveEmbedUrl":14,"description":56,"introduction":57,"organizer":18,"coOrganizer":5,"sponsor":16,"startTime":58,"endTime":59,"status":22,"dashboardVisibility":60,"createdAt":58,"updatedAt":61},"019eeeff-6b00-7d55-a629-efafded3e232","summer2026","2026年夏季InfiniTensor大模型与人工智能系统训练营","https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fuploads\u002F2026-06\u002F019eef7f-7816-7828-9309-79c2c61dd568.jpg?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=o29Dy5KMbkQVCWTVaFUX1%2F9v%2FI8%3D","由启元实验室发起的InfiniTensor大模型与人工智能系统训练营，面向开源社区、高校及产业界伙伴开放。活动以「普及AI全栈知识技术、培养工程实践与创新型人才、推广国产软硬件技术生态」为核心目标，助力国家人工智能产业高质量发展。","...","2026-06-22 08:00:00","2026-10-19 08:00:00","public","2026-10-12 08:00:00",{"id":63,"slug":64,"title":65,"logo":66,"publicLiveEmbedUrl":7,"description":67,"introduction":57,"organizer":18,"coOrganizer":5,"sponsor":68,"startTime":69,"endTime":70,"status":33,"dashboardVisibility":23,"createdAt":71,"updatedAt":72},"019af3f3-e06a-7245-aa8d-37dc99a69c73","winter2025","2025年冬季InfiniTensor大模型与人工智能系统训练营","https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fuploads\u002F2025-12\u002F019afc69-b7ca-7805-91fb-605429671c01.png?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=RF6et0tKpeNsR%2FwxsCjy7zBTZbU%3D","由启元实验室发起的InfiniTensor大模型与人工智能系统训练营，面向开源社区、高校及产业界伙伴开放。活动以「普及AI全栈知识技术、培养工程实践与创新型人才、推广国产软硬件技术生态」为核心目标，助力国家人工智能产业高质量发展。 \n","新华三技术有限公司","2025-12-25 08:00:00","2026-03-27 08:00:00","2025-12-06 08:00:00","2026-10-22 20:24:30",{"id":74,"slug":36,"title":75,"logo":76,"publicLiveEmbedUrl":7,"description":77,"introduction":57,"organizer":18,"coOrganizer":5,"sponsor":78,"startTime":79,"endTime":80,"status":81,"dashboardVisibility":23,"createdAt":82,"updatedAt":83},"01980342-208c-7803-b3f3-19e1d31960ba","2025年夏季InfiniTensor大模型与人工智能系统训练营","https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fuploads\u002F2025-07\u002F0198045e-28fe-78f0-95fe-23835ce58395.jpg?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=mArtxwAhCa0dE5Cm17SDDzrBtQ8%3D","InfiniTensor大模型与人工智能系统训练营由启元实验室及清华大学 AI 系统方向团队发起，面向开源社区、高校和产业界，普及人工智能各方面知识和技术，培养相关人才。训练营联合开源项目开发者、学术界大牛、工业界资深工程师参与授课与项目指导。课程采用「线上直播授课 + 在线答疑 + 项目实践辅导 」的方式进行，确保每位同学都能获得充分成长。训练营全程免费，通过视频、直播课、习题和项目实践，在人工智能飞速发展的背景下，为学员提供一窥深层技术的机会。","北京积算科技有限公司","2025-07-14 08:00:00","2025-09-30 08:00:00","upcoming","2025-07-13 08:00:00","2026-10-22 20:24:58",{"id":85,"slug":86,"title":87,"logo":88,"publicLiveEmbedUrl":7,"description":89,"introduction":57,"organizer":18,"coOrganizer":5,"sponsor":5,"startTime":90,"endTime":91,"status":81,"dashboardVisibility":23,"createdAt":92,"updatedAt":93},"01980cf9-a7d8-7796-ae86-0bbe05334add","winter2024","2024年冬季InfiniTensor大模型与人工智能系统训练营","https:\u002F\u002Ftesting-cdn.infinitensor.com\u002Fuploads\u002F2025-07\u002F01981269-ce23-7624-a287-9f07dd0d85f6.jpg","InfiniTensor大模型与人工智能系统训练营由清华大学发起，面向开源社区、高校和产业界，普及人工智能各方面知识和技术，培养相关人才。训练营全程免费，通过视频、直播课、习题和项目实践，在人工智能飞速发展的背景下，为学员提供一窥深层技术的机会。报名学员请阅读“导学”课程页的训练营介绍。","2025-01-05 08:00:00","2025-03-22 08:00:00","2025-07-15 08:00:00","2026-10-22 20:24:39",{"id":95,"slug":96,"title":97,"logo":98,"publicLiveEmbedUrl":7,"description":99,"introduction":57,"organizer":18,"coOrganizer":5,"sponsor":5,"startTime":100,"endTime":101,"status":81,"dashboardVisibility":23,"createdAt":92,"updatedAt":102},"01980c20-363a-7dc3-8f5a-58a68e08dcc4","summer2024","2024年夏季InfiniTensor大模型与人工智能系统训练营","https:\u002F\u002Ftesting-cdn.infinitensor.com\u002Fuploads\u002F2025-07\u002F01981269-fbfa-788a-afcd-17fa9be74ff9.jpg","InfiniTensor大模型与人工智能系统训练营由清华大学发起，面向开源社区和高校，普及人工智能各方面知识和技术，培养相关人才。训练营全程免费，通过课程、习题和项目实践，在人工智能飞速发展的背景下，为学员提供一窥深层技术的机会。","2024-07-20 08:00:00","2024-09-29 08:00:00","2026-10-22 20:24:49",[44],{"currentItem":105,"processedData":124},{"img":106,"keywords":5,"treeType":44,"description":107,"showStatus":44,"updateTime":108,"type":109,"title":110,"content":111,"nextArticle":112,"createTime":108,"sortOrder":116,"canonicalPath":117,"id":118,"contentType":119,"prevArticle":120},"https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fimages\u002FKnowledge_Base\u002FKB_56_fm.jpg?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=peAN9IVIHPVNUQhYKw%2FDIkRLPYA%3D","2025 InfiniTensor 冬季训练营 C++ 实践第3课：从 VLA 报错切入，详解 const 关键字、动态数组 capacity 机制、new\u002Fdelete 内存管理、构造\u002F析构函数、RAII 模式、模板类及访问封装，带你手写一个动态 Vector 容器。","2026-10-22 20:38:11",2,"2025 冬季 InfiniTensor 训练营｜C++ 实践课（三）","![](https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fimages\u002FKnowledge_Base\u002FKB_56_zw01.jpg?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=R8cYPhcijPL%2FNqhXSfu3N0W5ggs%3D)\r\n\r\n第一节课写的程序，数据输入（`input`）和计算（`calculate`）混合在一起，第二节课我们把这两块功能拆成了独立的函数，代码一下子清爽了不少。\r\n\r\n更关键的一步是引入了 **struct（结构体）**——把原来散落在各处的 `data` 和 `size` 两个变量打包进了一个结构体里。它让数据的组织方式从\"散装\"变成了\"整装\"，也为今天要讲的面向对象编程埋好了伏笔。\r\n\r\n在上节课的基础上继续往前推——先搭一个操作服务，能接收一串数字输入，然后对它们求和。这节课要做的，就是把代码重构得更规范、更接近真实项目中的写法。\r\n\r\n\r\n## VLA 与 const 关键字\r\n\r\n我们尝试进行一项操作——将数组初始化为零:\r\n\r\n```cpp\r\nint data[size] = {0};\r\n```\r\n结果编译器报错：\r\n\r\n```\r\nerror: variable \"data\" may not be initialized\r\n```\r\n等等，我明明写了 `= {0}`，怎么还说\"未初始化\"？\r\n\r\n问题出在 VLA（变长数组，Variable Length Array） 上。\r\n\r\n### 什么是 VLA？\r\n\r\nVLA 是指使用运行时确定的动态大小来创建数组的方式。而上文例子中的 `size` 虽然使用 `size_t` 类型初始化为 3，但对编译器来说，它是一个运行时才能确定的变量——它可以是 3、5、10或任何值。\r\n\r\n编译器的逻辑很简单：我在编译阶段就得知道你要分配多大的内存，你给我一个运行时才能确定的 `size`，我怎么分？\r\n\r\n### 解决方案？加 const：\r\n\r\n```cpp\r\nconst size_t size = 3;\r\nint data[size] = {0};  \u002F\u002F 编译通过\r\n```\r\n\r\n在这个例子中，`const size_t size = 3` 是编译期常量表达式，因此可以作为数组长度\r\n\r\n> C99 之后的 C 语言其实支持 VLA，但 C++ 标准不支持。这算是两门语言之间一个细微差别。\r\n\r\n## 动态数组与 capacity\r\n\r\n现实开发中，数据量从来不是固定的。今天处理 3 个 5 个，明天可能要处理成百上千个。固定大小的数组显然不够用。\r\n\r\n于是我们引入了一个关键概念——`capacity`（容量）。\r\n```\r\nstruct Vector {\r\n    double* data;   \u002F\u002F 存储数据的指针\r\n    int size;       \u002F\u002F 当前实际存储数据个数\r\n    int capacity;   \u002F\u002F 总容量\r\n};\r\n```\r\n\r\n**size ≠ capacity**\r\n\r\n- **size**：当前已存储的数据个数，即数组中实际有意义的元素数量（实际用了多少）\r\n- **capacity**：数组的总容量，即为数据分配的实际内存空间能容纳多少元素（最多能装多少）\r\n\r\n例如，你可以把 `capacity` 设为 100，而 `size` 根据实际存储数据量动态变化。只要不超过容量，就不用重新分配内存。\r\n\r\n为了使代码语义更加清晰，我们将结构体名称由 `numbers` 重命名为 **`vector`**(向量)，这是一个**动态变化**的数据结构。当然，你也可以叫它\"动态数组（dynamic array）\"，本质上一样。\r\n\r\n## 动态内存管理\r\n### new 与 delete 操作符\r\n\r\n有了 `capacity`，接下来要解决的就是：内存从哪来？\r\n\r\nC++ 的答案是 `new` 和 `delete`：\r\n\r\n```cpp\r\ndouble* data = new double[capacity];  \u002F\u002F 分配\r\ndelete[] data;                         \u002F\u002F 释放\r\n```\r\n\r\n>⚠️ 释放数组内必须用 `delete[]`，不能用 `delete`。\r\n\r\n如果用 `delete` 释放 `new[]` 分配的数组，会导致未定义行为，可能出现析构不完整、内存泄漏、程序崩溃等问题。\r\n\r\n### 构造函数与析构函数\r\n手动 `new` \u002F `delete` 太容易忘、容易出错。于是 C++ 引入了构造函数和析构函数：\r\n\r\n```cpp\r\nclass Vector {\r\npublic:\r\n    Vector() {    \u002F\u002F 构造函数：对象创建时自动执行，负责初始化\r\n    }\r\n    ~Vector() {   \u002F\u002F 析构函数：对象销毁时自动执行，负责清理\r\n    }\r\n};\r\n```\r\n\r\n- **构造函数**（Constructor）：名字和类名一样，无返回值，用于初始化。\r\n- **析构函数**（Destructor）：名字前加 **~**，无返回值，用于清理资源。\r\n\r\n还有一个更简洁高效的写法——**初始化列表**，在构造函数参数列表后面使用冒号，然后列出所有成员变量及其初始值，用逗号分隔：\r\n\r\n```cpp\r\nVector() : data(nullptr), size(0), capacity(0) {\r\n    \u002F\u002F 构造函数体可为空\r\n}\r\n```\r\n\r\n## 类的封装与访问控制\r\n### public 与 private\r\n**类（`class`）** 中的成员（包括变量和函数）可以设置为不同的访问级别，主要有两种：\r\n- **`public`**（公有）：可以被类的外部代码直接访问\r\n- **`private`**（私有）：只能被该类的成员函数访问，类的外部代码无法直接访问\r\n\r\n封装可以保护数据不被意外破坏，同时可以在成员函数中添加必要的检查和验证逻辑。\r\n```cpp\r\nclass Vector {\r\nprivate:       \u002F\u002F 私有：外部代码无法直接访问\r\n    double* data;\r\n    int size;\r\n    int capacity;\r\n\r\npublic:      \u002F\u002F 公有：提供对外接口\r\n    Vector();\r\n    ~Vector();    \u002F\u002F 向 Vector 中添加元素\r\n    void push_back(double value);    \u002F\u002F 获取指定位置的元素\r\n    double get(int index);\r\n};\r\n```\r\n\r\n### this 指针\r\n在类的成员函数中，存在一个特殊的指针——`this` 指针，指向当前对象（即调用该成员函数的对象）。遇到命名冲突时，`this-> `可以明确告诉编译器：我要的是成员变量，不是参数。\r\n```cpp\r\nvoid Vector::push_back(double value) {  \u002F\u002F 通过 this-> 明确访问当前对象的成员\r\n    this->data[this->size] = value;\r\n    this->size++;\r\n}\r\n```\r\n\r\n\r\n## RAII 模式\r\n把上面这些串起来，就得到了 C++ 里重要的编程惯用法（idiom）之一——**RAII**（Resource Acquisition Is Initialization，资源获取即初始化）。\r\n\r\n核心思想就一句话：\r\n\r\n**资源的获取绑定构造函数，资源的释放绑定析构函数。**\r\n\r\nRAII 模式带来三个巨大好处：\r\n\r\n- **自动管理资源**：不用手写释放代码，忘记释放的概率大幅降低；\r\n- **异常安全**：即使程序中途异常，栈上的局部对象也会被正确析构；\r\n- **避免内存泄漏**：资源生命周期 = 对象生命周期，对象销毁了，资源就不会泄露\r\n\r\n>`new` 配 `delete`，\r\n>`malloc` 配 `free`\r\n成对出现，缺一不可。\r\n\r\n## 模板类（Template）\r\n### 为什么需要模板？\r\n现在的 `Vector` 只能存 `double`。想存 `int`？再写一遍。想存 `string`？再写一遍。这显然不可接受。\r\n\r\n**模板（Template）** 就是来解决这个问题的。\r\n\r\n### 定义模板类\r\n使用 `template` 关键字可以定义模板类，将具体的类型替换为类型参数 T（也可以使用其他名称，如 U、ValueType 等）\r\n\r\n```cpp\r\ntemplate \u003Ctypename T>\r\nclass Vector {\r\nprivate:\r\n    T* data;     \u002F\u002F T 是占位符，表示任意类型\r\n    int size;\r\n    int capacity;\r\npublic:\r\n    void push_back(T value);    \u002F\u002F 参数类型为 T\r\n    T get(int index);    \u002F\u002F 返回类型为 T\r\n};\r\n```\r\n`typename` 关键字用于声明一个类型参数。在模板声明中，`class` 和 `typename `可互换，即 `template\u003Cclass T> `和 `template\u003Ctypename T> `是等价的。\r\n\r\n模板像是一个“类型工厂”——你给它一个类型，它给你生成一整套对应的代码。\r\n\r\n### 使用模板类\r\n实例化模板类时，需要在尖括号中指定具体的类型：\r\n```cpp\r\nVector\u003Cdouble> doubleVec;    \u002F\u002F 存储 double 类型\r\nVector\u003Cint> intVec;       \u002F\u002F 存储 int 类型\r\nVector\u003Cstd::string> strVec;    \u002F\u002F 存储字符串\r\n```\r\n>模板类的声明和实现通常都要放在 **头文件（`.h\u002F.hpp`）** 里。因为编译器在实例化时需要看到完整定义，这与普通类将声明和实现分离不同，是模板机制的特殊要求。\r\n\r\n## 头文件与源文件的分离\r\n### 传统的 .h 和 .cpp 分离\r\n对于非模板类，通常将类的声明放在头文件（`.h\u002F.hpp`）中，将实现放在源文件（`.cpp`）中。这种分离有几个好处：\r\n\r\n- **代码组织清晰**：声明与实现分离，便于管理\r\n- **编译加速**：修改实现文件不需要重新编译使用该类的代码\r\n- **信息隐藏**：向使用者隐藏实现细节\r\n\r\n### 模板类的特殊性\r\n由于编译器在实例化模板时需要看到完整的定义，模板类需要特殊处理，声明和实现通常都放在头文件中。\r\n\r\n这种做法虽然打破了传统的分离原则，但能确保编译器在实例化模板时能够访问完整的代码。这也是 C++ 模板系统的一个独特之处。\r\n\r\n## Git 版本控制基础\r\n### 暂存与提交\r\n在开发过程中，使用 `Git` 进行版本控制是一个好习惯。我们通常遵循以下流程：\r\n- `git add`：将文件添加到暂存区\r\n- `git commit`：将暂存区的修改提交到本地仓库\r\n- 每节课结束时提交一次，这样就可以清晰地知道上一节课结束时的代码状态\r\n\r\n### git stash 命令\r\n`git stash` 可以暂存当前未提交的修改，以便切换到其他分支或进行其他操作。\r\n\r\n`git stash` 默认会暂存已跟踪文件的修改，包括已暂存和未暂存的修改，但不会包含未跟踪文件。若要同时暂存未跟踪文，可使用 `git stash -u` 或 `git stash --include-untracked `来包含未跟踪的文件。\r\n\r\n\r\n## 课后 Q&A\r\n#### Q1：波浪线（~）在构造函数和析构函数中有什么区别？\r\n\r\n>构造函数不加波浪线，其名称与类名相同。析构函数在名称前加波浪线（~），表示这是与构造函数对应的析构函数。\r\n\r\n#### Q2：`include` 与 Python 的 `import` 类似吗？\r\n\r\n>不完全类似，但功能相近。`include` 更接近于在预处理阶段把目标文件内容“复制粘贴”到当前文件中；而 Python 的 `import` 是模块加载机制，不是简单的文本插入。。\r\n\r\n#### Q3：模板参数只能是类型吗？\r\n\r\n>不是。模板参数除了类型参数（如 `typename T`）外，还可以是非类型的常量参数（如 `template\u003Cint N>`）。不过非类型参数有一些限制，实际使用中类型参数更为常见。\r\n\r\n### 更多课程细节查看\r\n本次课程回放可访问 InfiniTensor 官网：https:\u002F\u002Fwww.infinitensor.com 查看，或点击 **【阅读原文】** 跳转至 InfiniTensor 官网。\r\n\r\n>觉得有用就转发给也在学 C++ 的朋友吧！ 新一期训练营也将于近期开启报名，欢迎关注公众号，第一时间获取课程与报名信息📢\r\n\r\n## 关注与交流\r\n![](https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fimages\u002FKnowledge_Base\u002FKB_56_zw02.jpg?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=twjNwmqqvcMXJwPo8jAbwR%2Br6QE%3D)",{"publishTime":7,"createTime":108,"canonicalPath":113,"id":114,"title":115},"\u002Fstudy-material\u002Fstudy-55","study-55","2025 冬季 InfiniTensor 训练营｜C++ 实践课（二）",53,"\u002Fstudy-material\u002Fstudy-56","study-56","markdown",{"publishTime":7,"createTime":108,"canonicalPath":121,"id":122,"title":123},"\u002Fstudy-material\u002Fstudy-57","study-57","2025 冬季 InfiniTensor 训练营｜Python 入门",{"htmlContent":125,"headings":126},"\u003Cp>\u003Cimg src=\"https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fimages\u002FKnowledge_Base\u002FKB_56_zw01.jpg?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=R8cYPhcijPL%2FNqhXSfu3N0W5ggs%3D\" alt=\"\">\u003C\u002Fp>\n\u003Cp>第一节课写的程序，数据输入（\u003Ccode>input\u003C\u002Fcode>）和计算（\u003Ccode>calculate\u003C\u002Fcode>）混合在一起，第二节课我们把这两块功能拆成了独立的函数，代码一下子清爽了不少。\u003C\u002Fp>\n\u003Cp>更关键的一步是引入了 \u003Cstrong>struct（结构体）\u003C\u002Fstrong>——把原来散落在各处的 \u003Ccode>data\u003C\u002Fcode> 和 \u003Ccode>size\u003C\u002Fcode> 两个变量打包进了一个结构体里。它让数据的组织方式从&quot;散装&quot;变成了&quot;整装&quot;，也为今天要讲的面向对象编程埋好了伏笔。\u003C\u002Fp>\n\u003Cp>在上节课的基础上继续往前推——先搭一个操作服务，能接收一串数字输入，然后对它们求和。这节课要做的，就是把代码重构得更规范、更接近真实项目中的写法。\u003C\u002Fp>\n\u003Ch2 id=\"vla-与-const-关键字\">\u003Ca class=\"anchor\" href=\"#vla-与-const-关键字\" aria-label=\"跳转到标题：VLA 与 const 关键字\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>VLA 与 const 关键字\u003C\u002Fh2>\u003Cp>我们尝试进行一项操作——将数组初始化为零:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">int data[size] = {0};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>结果编译器报错：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>error: variable &quot;data&quot; may not be initialized\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>等等，我明明写了 \u003Ccode>= {0}\u003C\u002Fcode>，怎么还说&quot;未初始化&quot;？\u003C\u002Fp>\n\u003Cp>问题出在 VLA（变长数组，Variable Length Array） 上。\u003C\u002Fp>\n\u003Ch3 id=\"什么是-vla\">\u003Ca class=\"anchor\" href=\"#什么是-vla\" aria-label=\"跳转到标题：什么是 VLA？\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>什么是 VLA？\u003C\u002Fh3>\u003Cp>VLA 是指使用运行时确定的动态大小来创建数组的方式。而上文例子中的 \u003Ccode>size\u003C\u002Fcode> 虽然使用 \u003Ccode>size_t\u003C\u002Fcode> 类型初始化为 3，但对编译器来说，它是一个运行时才能确定的变量——它可以是 3、5、10或任何值。\u003C\u002Fp>\n\u003Cp>编译器的逻辑很简单：我在编译阶段就得知道你要分配多大的内存，你给我一个运行时才能确定的 \u003Ccode>size\u003C\u002Fcode>，我怎么分？\u003C\u002Fp>\n\u003Ch3 id=\"解决方案-加-const\">\u003Ca class=\"anchor\" href=\"#解决方案-加-const\" aria-label=\"跳转到标题：解决方案？加 const：\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>解决方案？加 const：\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-cpp\">const size_t size = 3;\nint data[size] = {0};  \u002F\u002F 编译通过\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>在这个例子中，\u003Ccode>const size_t size = 3\u003C\u002Fcode> 是编译期常量表达式，因此可以作为数组长度\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>C99 之后的 C 语言其实支持 VLA，但 C++ 标准不支持。这算是两门语言之间一个细微差别。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"动态数组与-capacity\">\u003Ca class=\"anchor\" href=\"#动态数组与-capacity\" aria-label=\"跳转到标题：动态数组与 capacity\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>动态数组与 capacity\u003C\u002Fh2>\u003Cp>现实开发中，数据量从来不是固定的。今天处理 3 个 5 个，明天可能要处理成百上千个。固定大小的数组显然不够用。\u003C\u002Fp>\n\u003Cp>于是我们引入了一个关键概念——\u003Ccode>capacity\u003C\u002Fcode>（容量）。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>struct Vector {\n    double* data;   \u002F\u002F 存储数据的指针\n    int size;       \u002F\u002F 当前实际存储数据个数\n    int capacity;   \u002F\u002F 总容量\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>size ≠ capacity\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>size\u003C\u002Fstrong>：当前已存储的数据个数，即数组中实际有意义的元素数量（实际用了多少）\u003C\u002Fli>\n\u003Cli>\u003Cstrong>capacity\u003C\u002Fstrong>：数组的总容量，即为数据分配的实际内存空间能容纳多少元素（最多能装多少）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>例如，你可以把 \u003Ccode>capacity\u003C\u002Fcode> 设为 100，而 \u003Ccode>size\u003C\u002Fcode> 根据实际存储数据量动态变化。只要不超过容量，就不用重新分配内存。\u003C\u002Fp>\n\u003Cp>为了使代码语义更加清晰，我们将结构体名称由 \u003Ccode>numbers\u003C\u002Fcode> 重命名为 \u003Cstrong>\u003Ccode>vector\u003C\u002Fcode>\u003C\u002Fstrong>(向量)，这是一个\u003Cstrong>动态变化\u003C\u002Fstrong>的数据结构。当然，你也可以叫它&quot;动态数组（dynamic array）&quot;，本质上一样。\u003C\u002Fp>\n\u003Ch2 id=\"动态内存管理\">\u003Ca class=\"anchor\" href=\"#动态内存管理\" aria-label=\"跳转到标题：动态内存管理\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>动态内存管理\u003C\u002Fh2>\u003Ch3 id=\"new-与-delete-操作符\">\u003Ca class=\"anchor\" href=\"#new-与-delete-操作符\" aria-label=\"跳转到标题：new 与 delete 操作符\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>new 与 delete 操作符\u003C\u002Fh3>\u003Cp>有了 \u003Ccode>capacity\u003C\u002Fcode>，接下来要解决的就是：内存从哪来？\u003C\u002Fp>\n\u003Cp>C++ 的答案是 \u003Ccode>new\u003C\u002Fcode> 和 \u003Ccode>delete\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">double* data = new double[capacity];  \u002F\u002F 分配\ndelete[] data;                         \u002F\u002F 释放\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\n\u003Cp>⚠️ 释放数组内必须用 \u003Ccode>delete[]\u003C\u002Fcode>，不能用 \u003Ccode>delete\u003C\u002Fcode>。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>如果用 \u003Ccode>delete\u003C\u002Fcode> 释放 \u003Ccode>new[]\u003C\u002Fcode> 分配的数组，会导致未定义行为，可能出现析构不完整、内存泄漏、程序崩溃等问题。\u003C\u002Fp>\n\u003Ch3 id=\"构造函数与析构函数\">\u003Ca class=\"anchor\" href=\"#构造函数与析构函数\" aria-label=\"跳转到标题：构造函数与析构函数\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>构造函数与析构函数\u003C\u002Fh3>\u003Cp>手动 \u003Ccode>new\u003C\u002Fcode> \u002F \u003Ccode>delete\u003C\u002Fcode> 太容易忘、容易出错。于是 C++ 引入了构造函数和析构函数：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">class Vector {\npublic:\n    Vector() {    \u002F\u002F 构造函数：对象创建时自动执行，负责初始化\n    }\n    ~Vector() {   \u002F\u002F 析构函数：对象销毁时自动执行，负责清理\n    }\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul>\n\u003Cli>\u003Cstrong>构造函数\u003C\u002Fstrong>（Constructor）：名字和类名一样，无返回值，用于初始化。\u003C\u002Fli>\n\u003Cli>\u003Cstrong>析构函数\u003C\u002Fstrong>（Destructor）：名字前加 \u003Cstrong>~\u003C\u002Fstrong>，无返回值，用于清理资源。\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>还有一个更简洁高效的写法——\u003Cstrong>初始化列表\u003C\u002Fstrong>，在构造函数参数列表后面使用冒号，然后列出所有成员变量及其初始值，用逗号分隔：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">Vector() : data(nullptr), size(0), capacity(0) {\n    \u002F\u002F 构造函数体可为空\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"类的封装与访问控制\">\u003Ca class=\"anchor\" href=\"#类的封装与访问控制\" aria-label=\"跳转到标题：类的封装与访问控制\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>类的封装与访问控制\u003C\u002Fh2>\u003Ch3 id=\"public-与-private\">\u003Ca class=\"anchor\" href=\"#public-与-private\" aria-label=\"跳转到标题：public 与 private\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>public 与 private\u003C\u002Fh3>\u003Cp>\u003Cstrong>类（\u003Ccode>class\u003C\u002Fcode>）\u003C\u002Fstrong> 中的成员（包括变量和函数）可以设置为不同的访问级别，主要有两种：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Ccode>public\u003C\u002Fcode>\u003C\u002Fstrong>（公有）：可以被类的外部代码直接访问\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>private\u003C\u002Fcode>\u003C\u002Fstrong>（私有）：只能被该类的成员函数访问，类的外部代码无法直接访问\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>封装可以保护数据不被意外破坏，同时可以在成员函数中添加必要的检查和验证逻辑。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">class Vector {\nprivate:       \u002F\u002F 私有：外部代码无法直接访问\n    double* data;\n    int size;\n    int capacity;\n\npublic:      \u002F\u002F 公有：提供对外接口\n    Vector();\n    ~Vector();    \u002F\u002F 向 Vector 中添加元素\n    void push_back(double value);    \u002F\u002F 获取指定位置的元素\n    double get(int index);\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"this-指针\">\u003Ca class=\"anchor\" href=\"#this-指针\" aria-label=\"跳转到标题：this 指针\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>this 指针\u003C\u002Fh3>\u003Cp>在类的成员函数中，存在一个特殊的指针——\u003Ccode>this\u003C\u002Fcode> 指针，指向当前对象（即调用该成员函数的对象）。遇到命名冲突时，\u003Ccode>this-&gt; \u003C\u002Fcode>可以明确告诉编译器：我要的是成员变量，不是参数。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">void Vector::push_back(double value) {  \u002F\u002F 通过 this-&gt; 明确访问当前对象的成员\n    this-&gt;data[this-&gt;size] = value;\n    this-&gt;size++;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"raii-模式\">\u003Ca class=\"anchor\" href=\"#raii-模式\" aria-label=\"跳转到标题：RAII 模式\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>RAII 模式\u003C\u002Fh2>\u003Cp>把上面这些串起来，就得到了 C++ 里重要的编程惯用法（idiom）之一——\u003Cstrong>RAII\u003C\u002Fstrong>（Resource Acquisition Is Initialization，资源获取即初始化）。\u003C\u002Fp>\n\u003Cp>核心思想就一句话：\u003C\u002Fp>\n\u003Cp>\u003Cstrong>资源的获取绑定构造函数，资源的释放绑定析构函数。\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>RAII 模式带来三个巨大好处：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>自动管理资源\u003C\u002Fstrong>：不用手写释放代码，忘记释放的概率大幅降低；\u003C\u002Fli>\n\u003Cli>\u003Cstrong>异常安全\u003C\u002Fstrong>：即使程序中途异常，栈上的局部对象也会被正确析构；\u003C\u002Fli>\n\u003Cli>\u003Cstrong>避免内存泄漏\u003C\u002Fstrong>：资源生命周期 = 对象生命周期，对象销毁了，资源就不会泄露\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cblockquote>\n\u003Cp>\u003Ccode>new\u003C\u002Fcode> 配 \u003Ccode>delete\u003C\u002Fcode>，\u003Cbr>\u003Ccode>malloc\u003C\u002Fcode> 配 \u003Ccode>free\u003C\u002Fcode>\u003Cbr>成对出现，缺一不可。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"模板类-template\">\u003Ca class=\"anchor\" href=\"#模板类-template\" aria-label=\"跳转到标题：模板类（Template）\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>模板类（Template）\u003C\u002Fh2>\u003Ch3 id=\"为什么需要模板\">\u003Ca class=\"anchor\" href=\"#为什么需要模板\" aria-label=\"跳转到标题：为什么需要模板？\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>为什么需要模板？\u003C\u002Fh3>\u003Cp>现在的 \u003Ccode>Vector\u003C\u002Fcode> 只能存 \u003Ccode>double\u003C\u002Fcode>。想存 \u003Ccode>int\u003C\u002Fcode>？再写一遍。想存 \u003Ccode>string\u003C\u002Fcode>？再写一遍。这显然不可接受。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>模板（Template）\u003C\u002Fstrong> 就是来解决这个问题的。\u003C\u002Fp>\n\u003Ch3 id=\"定义模板类\">\u003Ca class=\"anchor\" href=\"#定义模板类\" aria-label=\"跳转到标题：定义模板类\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>定义模板类\u003C\u002Fh3>\u003Cp>使用 \u003Ccode>template\u003C\u002Fcode> 关键字可以定义模板类，将具体的类型替换为类型参数 T（也可以使用其他名称，如 U、ValueType 等）\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">template &lt;typename T&gt;\nclass Vector {\nprivate:\n    T* data;     \u002F\u002F T 是占位符，表示任意类型\n    int size;\n    int capacity;\npublic:\n    void push_back(T value);    \u002F\u002F 参数类型为 T\n    T get(int index);    \u002F\u002F 返回类型为 T\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>typename\u003C\u002Fcode> 关键字用于声明一个类型参数。在模板声明中，\u003Ccode>class\u003C\u002Fcode> 和 \u003Ccode>typename \u003C\u002Fcode>可互换，即 \u003Ccode>template&lt;class T&gt; \u003C\u002Fcode>和 \u003Ccode>template&lt;typename T&gt; \u003C\u002Fcode>是等价的。\u003C\u002Fp>\n\u003Cp>模板像是一个“类型工厂”——你给它一个类型，它给你生成一整套对应的代码。\u003C\u002Fp>\n\u003Ch3 id=\"使用模板类\">\u003Ca class=\"anchor\" href=\"#使用模板类\" aria-label=\"跳转到标题：使用模板类\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>使用模板类\u003C\u002Fh3>\u003Cp>实例化模板类时，需要在尖括号中指定具体的类型：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">Vector&lt;double&gt; doubleVec;    \u002F\u002F 存储 double 类型\nVector&lt;int&gt; intVec;       \u002F\u002F 存储 int 类型\nVector&lt;std::string&gt; strVec;    \u002F\u002F 存储字符串\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\n\u003Cp>模板类的声明和实现通常都要放在 \u003Cstrong>头文件（\u003Ccode>.h\u002F.hpp\u003C\u002Fcode>）\u003C\u002Fstrong> 里。因为编译器在实例化时需要看到完整定义，这与普通类将声明和实现分离不同，是模板机制的特殊要求。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"头文件与源文件的分离\">\u003Ca class=\"anchor\" href=\"#头文件与源文件的分离\" aria-label=\"跳转到标题：头文件与源文件的分离\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>头文件与源文件的分离\u003C\u002Fh2>\u003Ch3 id=\"传统的-h-和-cpp-分离\">\u003Ca class=\"anchor\" href=\"#传统的-h-和-cpp-分离\" aria-label=\"跳转到标题：传统的 .h 和 .cpp 分离\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>传统的 .h 和 .cpp 分离\u003C\u002Fh3>\u003Cp>对于非模板类，通常将类的声明放在头文件（\u003Ccode>.h\u002F.hpp\u003C\u002Fcode>）中，将实现放在源文件（\u003Ccode>.cpp\u003C\u002Fcode>）中。这种分离有几个好处：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>代码组织清晰\u003C\u002Fstrong>：声明与实现分离，便于管理\u003C\u002Fli>\n\u003Cli>\u003Cstrong>编译加速\u003C\u002Fstrong>：修改实现文件不需要重新编译使用该类的代码\u003C\u002Fli>\n\u003Cli>\u003Cstrong>信息隐藏\u003C\u002Fstrong>：向使用者隐藏实现细节\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"模板类的特殊性\">\u003Ca class=\"anchor\" href=\"#模板类的特殊性\" aria-label=\"跳转到标题：模板类的特殊性\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>模板类的特殊性\u003C\u002Fh3>\u003Cp>由于编译器在实例化模板时需要看到完整的定义，模板类需要特殊处理，声明和实现通常都放在头文件中。\u003C\u002Fp>\n\u003Cp>这种做法虽然打破了传统的分离原则，但能确保编译器在实例化模板时能够访问完整的代码。这也是 C++ 模板系统的一个独特之处。\u003C\u002Fp>\n\u003Ch2 id=\"git-版本控制基础\">\u003Ca class=\"anchor\" href=\"#git-版本控制基础\" aria-label=\"跳转到标题：Git 版本控制基础\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>Git 版本控制基础\u003C\u002Fh2>\u003Ch3 id=\"暂存与提交\">\u003Ca class=\"anchor\" href=\"#暂存与提交\" aria-label=\"跳转到标题：暂存与提交\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>暂存与提交\u003C\u002Fh3>\u003Cp>在开发过程中，使用 \u003Ccode>Git\u003C\u002Fcode> 进行版本控制是一个好习惯。我们通常遵循以下流程：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>git add\u003C\u002Fcode>：将文件添加到暂存区\u003C\u002Fli>\n\u003Cli>\u003Ccode>git commit\u003C\u002Fcode>：将暂存区的修改提交到本地仓库\u003C\u002Fli>\n\u003Cli>每节课结束时提交一次，这样就可以清晰地知道上一节课结束时的代码状态\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"git-stash-命令\">\u003Ca class=\"anchor\" href=\"#git-stash-命令\" aria-label=\"跳转到标题：git stash 命令\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>git stash 命令\u003C\u002Fh3>\u003Cp>\u003Ccode>git stash\u003C\u002Fcode> 可以暂存当前未提交的修改，以便切换到其他分支或进行其他操作。\u003C\u002Fp>\n\u003Cp>\u003Ccode>git stash\u003C\u002Fcode> 默认会暂存已跟踪文件的修改，包括已暂存和未暂存的修改，但不会包含未跟踪文件。若要同时暂存未跟踪文，可使用 \u003Ccode>git stash -u\u003C\u002Fcode> 或 \u003Ccode>git stash --include-untracked \u003C\u002Fcode>来包含未跟踪的文件。\u003C\u002Fp>\n\u003Ch2 id=\"课后-q-amp-a\">\u003Ca class=\"anchor\" href=\"#课后-q-amp-a\" aria-label=\"跳转到标题：课后 Q&amp;amp;A\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>课后 Q&amp;A\u003C\u002Fh2>\u003Ch4 id=\"q1-波浪线-在构造函数和析构函数中有什么区别\">\u003Ca class=\"anchor\" href=\"#q1-波浪线-在构造函数和析构函数中有什么区别\" aria-label=\"跳转到标题：Q1：波浪线（~）在构造函数和析构函数中有什么区别？\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>Q1：波浪线（~）在构造函数和析构函数中有什么区别？\u003C\u002Fh4>\u003Cblockquote>\n\u003Cp>构造函数不加波浪线，其名称与类名相同。析构函数在名称前加波浪线（~），表示这是与构造函数对应的析构函数。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch4 id=\"q2-include-与-python-的-import-类似吗\">\u003Ca class=\"anchor\" href=\"#q2-include-与-python-的-import-类似吗\" aria-label=\"跳转到标题：Q2：include 与 Python 的 import 类似吗？\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>Q2：\u003Ccode>include\u003C\u002Fcode> 与 Python 的 \u003Ccode>import\u003C\u002Fcode> 类似吗？\u003C\u002Fh4>\u003Cblockquote>\n\u003Cp>不完全类似，但功能相近。\u003Ccode>include\u003C\u002Fcode> 更接近于在预处理阶段把目标文件内容“复制粘贴”到当前文件中；而 Python 的 \u003Ccode>import\u003C\u002Fcode> 是模块加载机制，不是简单的文本插入。。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch4 id=\"q3-模板参数只能是类型吗\">\u003Ca class=\"anchor\" href=\"#q3-模板参数只能是类型吗\" aria-label=\"跳转到标题：Q3：模板参数只能是类型吗？\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>Q3：模板参数只能是类型吗？\u003C\u002Fh4>\u003Cblockquote>\n\u003Cp>不是。模板参数除了类型参数（如 \u003Ccode>typename T\u003C\u002Fcode>）外，还可以是非类型的常量参数（如 \u003Ccode>template&lt;int N&gt;\u003C\u002Fcode>）。不过非类型参数有一些限制，实际使用中类型参数更为常见。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch3 id=\"更多课程细节查看\">\u003Ca class=\"anchor\" href=\"#更多课程细节查看\" aria-label=\"跳转到标题：更多课程细节查看\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>更多课程细节查看\u003C\u002Fh3>\u003Cp>本次课程回放可访问 InfiniTensor 官网：\u003Ca href=\"https:\u002F\u002Fwww.infinitensor.com\">https:\u002F\u002Fwww.infinitensor.com\u003C\u002Fa> 查看，或点击 \u003Cstrong>【阅读原文】\u003C\u002Fstrong> 跳转至 InfiniTensor 官网。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>觉得有用就转发给也在学 C++ 的朋友吧！ 新一期训练营也将于近期开启报名，欢迎关注公众号，第一时间获取课程与报名信息📢\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2 id=\"关注与交流\">\u003Ca class=\"anchor\" href=\"#关注与交流\" aria-label=\"跳转到标题：关注与交流\">\u003Cspan class=\"octicon octicon-link\">\u003C\u002Fspan>\u003C\u002Fa>关注与交流\u003C\u002Fh2>\u003Cp>\u003Cimg src=\"https:\u002F\u002Foss.infinitensor.com\u002Fprod\u002Fimages\u002FKnowledge_Base\u002FKB_56_zw02.jpg?Expires=1792752820&OSSAccessKeyId=LTAI5t9R6uzvTa69CT92cFvV&Signature=twjNwmqqvcMXJwPo8jAbwR%2Br6QE%3D\" alt=\"\">\u003C\u002Fp>\n",[127,130,133,136,139,141,144,146,148,151,154,157,160,163,165,167,169,172,174,177,179,182,185,189,192,195,197],{"id":128,"text":129,"level":109},"vla-与-const-关键字","VLA 与 const 关键字",{"id":131,"text":132,"level":9},"什么是-vla","什么是 VLA？",{"id":134,"text":135,"level":9},"解决方案-加-const","解决方案？加 const：",{"id":137,"text":138,"level":109},"动态数组与-capacity","动态数组与 capacity",{"id":140,"text":140,"level":109},"动态内存管理",{"id":142,"text":143,"level":9},"new-与-delete-操作符","new 与 delete 操作符",{"id":145,"text":145,"level":9},"构造函数与析构函数",{"id":147,"text":147,"level":109},"类的封装与访问控制",{"id":149,"text":150,"level":9},"public-与-private","public 与 private",{"id":152,"text":153,"level":9},"this-指针","this 指针",{"id":155,"text":156,"level":109},"raii-模式","RAII 模式",{"id":158,"text":159,"level":109},"模板类-template","模板类（Template）",{"id":161,"text":162,"level":9},"为什么需要模板","为什么需要模板？",{"id":164,"text":164,"level":9},"定义模板类",{"id":166,"text":166,"level":9},"使用模板类",{"id":168,"text":168,"level":109},"头文件与源文件的分离",{"id":170,"text":171,"level":9},"传统的-h-和-cpp-分离","传统的 .h 和 .cpp 分离",{"id":173,"text":173,"level":9},"模板类的特殊性",{"id":175,"text":176,"level":109},"git-版本控制基础","Git 版本控制基础",{"id":178,"text":178,"level":9},"暂存与提交",{"id":180,"text":181,"level":9},"git-stash-命令","git stash 命令",{"id":183,"text":184,"level":109},"课后-q-amp-a","课后 Q&amp;A",{"id":186,"text":187,"level":188},"q1-波浪线-在构造函数和析构函数中有什么区别","Q1：波浪线（~）在构造函数和析构函数中有什么区别？",4,{"id":190,"text":191,"level":188},"q2-include-与-python-的-import-类似吗","Q2：include 与 Python 的 import 类似吗？",{"id":193,"text":194,"level":188},"q3-模板参数只能是类型吗","Q3：模板参数只能是类型吗？",{"id":196,"text":196,"level":9},"更多课程细节查看",{"id":198,"text":198,"level":109},"关注与交流"]