【C++】零基础入门 · 第 12 节:模板与 STL 入门 到目前为止我们已经学会了变量、函数、类、指针、文件操作等核心知识。这一节我们来解锁 C 中两个超级实用的特性模板Template和STL标准模板库。它们能让你的代码更简洁、更通用、更强大1. 为什么需要模板想象一下你写了一个函数用来求两个数的最大值。intmaxVal(inta,intb){return(ab)?a:b;}很好用但如果我想求两个double的最大值呢两个char的最大值呢你可能会说再写几个重载函数呗。doublemaxVal(doublea,doubleb){return(ab)?a:b;}可是这样每多一种类型就要多写一个函数太麻烦了。模板就是用来解决这个问题的——你只需要写一次编译器会自动帮你生成适用于各种类型的版本。2. 函数模板2.1 基本语法函数模板的写法非常简单在函数前面加上template typename T就行#includeiostreamusingnamespacestd;templatetypenameTTmaxVal(T a,T b){return(ab)?a:b;}intmain(){coutint: maxVal(3,7)endl;coutdouble: maxVal(3.14,2.71)endl;coutchar: maxVal(a,z)endl;return0;}输出int: 7 double: 3.14 char: z这里的T就是一个类型占位符。当你调用maxVal(3, 7)时编译器发现参数是int就把T替换成int调用maxVal(3.14, 2.71)时T就变成double。你可以把T想象成一个待填写的类型空格编译器会根据你的调用自动填上正确的类型。2.2 多个模板参数模板参数也可以有多个#includeiostreamusingnamespacestd;templatetypenameT1,typenameT2voidprintPair(T1 a,T2 b){cout(a, b)endl;}intmain(){printPair(1,3.14);printPair(hello,42);printPair(A,true);return0;}输出(1, 3.14) (hello, 42) (A, 1)3. 类模板函数可以模板化类当然也可以3.1 一个简单的 Pair 类模板#includeiostream#includestringusingnamespacestd;templatetypenameT1,typenameT2classPair{public:T1 first;T2 second;Pair(T1 a,T2 b):first(a),second(b){}voidprint()const{cout(first, second)endl;}};intmain(){Pairint,doublep1(1,3.14);Pairstring,intp2(年龄,18);p1.print();p2.print();return0;}输出(1, 3.14) (年龄, 18)注意使用类模板时需要在尖括号里显式指定类型比如Pairint, double。这和函数模板不同函数模板通常可以自动推导类型但类模板一般需要你手动告诉它。3.2 一个简单的 Stack 类模板再来一个稍微实用一点的例子——用模板实现一个简单的栈Stack#includeiostream#includestringusingnamespacestd;templatetypenameTclassSimpleStack{private:T data[100];inttopIndex;public:SimpleStack():topIndex(-1){}voidpush(constTval){if(topIndex99){cout栈已满endl;return;}data[topIndex]val;}Tpop(){if(topIndex0){cout栈为空endl;returnT();}returndata[topIndex--];}boolempty()const{returntopIndex0;}};intmain(){// 整数栈SimpleStackintintStack;intStack.push(10);intStack.push(20);intStack.push(30);cout弹出: intStack.pop()endl;// 30cout弹出: intStack.pop()endl;// 20// 字符串栈SimpleStackstringstrStack;strStack.push(你好);strStack.push(世界);cout弹出: strStack.pop()endl;// 世界cout弹出: strStack.pop()endl;// 你好return0;}输出弹出: 30 弹出: 20 弹出: 世界 弹出: 你好同一个SimpleStack类通过模板就能存放不同类型的数据这就是模板的威力4. 什么是 STLSTLStandard Template Library标准模板库是 C 自带的一个工具箱里面包含了大量常用的数据结构和算法。你可以把它想象成一个超级工具箱需要收纳就用vector需要查字典就用map需要排序就用sort——都不用自己从零造轮子。STL 主要由三部分组成容器Container用来存放数据比如vector、map、set算法Algorithm用来处理数据比如sort、find迭代器Iterator连接容器和算法的桥梁5. STL 容器vectorvector是 STL 中最常用的容器可以理解为一个自动扩容的数组。#includeiostream#includevectorusingnamespacestd;intmain(){// 创建一个空的 vectorvectorintnums;// 往末尾添加元素nums.push_back(10);nums.push_back(20);nums.push_back(30);nums.push_back(40);// 用下标访问cout第一个元素: nums[0]endl;// 获取大小cout大小: nums.size()endl;// 遍历范围 for 循环cout所有元素: ;for(intn:nums){coutn ;}coutendl;// 删除最后一个元素nums.pop_back();cout删除后大小: nums.size()endl;return0;}输出第一个元素: 10 大小: 4 所有元素: 10 20 30 40 删除后大小: 3和普通数组相比vector的好处是你不需要提前知道要存多少数据它可以自动增长。push_back加一个pop_back删一个size()问大小——非常方便。6. STL 容器mapmap就像一本字典它存储的是键值对key-value pair你给它一个键它返回对应的值。#includeiostream#includemap#includestringusingnamespacestd;intmain(){mapstring,intages;// 添加键值对ages[小明]18;ages[小红]20;ages[小刚]19;// 通过键访问值cout小明的年龄: ages[小明]endl;// 查找键是否存在if(ages.find(小红)!ages.end()){cout小红存在年龄: ages[小红]endl;}// 遍历 mapfor(constautopair:ages){coutpair.first - pair.secondendl;}return0;}输出小明的年龄: 18 小红存在年龄: 20 小刚 - 19 小明 - 18 小红 - 20map内部会自动按键排序这里按字符串的字典序查找速度也很快。适合需要通过名字找数据的场景。7. STL 容器setset是一个自动去重的有序集合。你往里面丢元素它会自动帮你排好序并且去掉重复的。#includeiostream#includesetusingnamespacestd;intmain(){setints;s.insert(30);s.insert(10);s.insert(20);s.insert(10);// 重复不会插入s.insert(30);// 重复不会插入cout大小: s.size()endl;// 3cout元素: ;for(intn:s){coutn ;}coutendl;// 查找if(s.count(20)){cout20 存在endl;}return0;}输出大小: 3 元素: 10 20 30 20 存在set非常适合需要不重复和自动排序的场景比如记录一组不重复的学号。8. STL 算法sort 和 findSTL 提供了很多现成的算法函数配合容器和迭代器使用功能强大。8.1 sort 排序#includeiostream#includevector#includealgorithmusingnamespacestd;intmain(){vectorintnums{5,2,8,1,9,3};// 升序排序sort(nums.begin(),nums.end());cout升序: ;for(intn:nums){coutn ;}coutendl;// 降序排序sort(nums.begin(),nums.end(),greaterint());cout降序: ;for(intn:nums){coutn ;}coutendl;return0;}输出升序: 1 2 3 5 8 9 降序: 9 8 5 3 2 1sort接收两个迭代器参数表示要排序的范围begin()指向第一个元素end()指向最后一个元素的后面。greaterint()表示用大于来比较从而实现降序。8.2 find 查找#includeiostream#includevector#includealgorithmusingnamespacestd;intmain(){vectorintnums{10,20,30,40,50};autoitfind(nums.begin(),nums.end(),30);if(it!nums.end()){cout找到了下标是: it-nums.begin()endl;}else{cout没找到endl;}return0;}输出找到了下标是: 2find返回一个迭代器如果找到了就指向那个元素没找到就返回end()。9. 为什么 STL 值得学STL 的好处可以用一句话概括别人帮你写好了你直接用就行。高效STL 的实现经过了大量优化性能比你自己写的代码通常更好可靠经过了几十年的测试和验证Bug 极少通用学会了vector、map、sort你就能解决大部分编程问题面试必问STL 是 C 面试中的高频考点10. 总结这一节我们学习了 C 中两个非常重要的特性模板让我们写出与类型无关的通用代码。函数模板用template typename T声明编译器会自动推导类型类模板需要在使用时显式指定类型。STL是 C 内置的工具箱包含容器、算法和迭代器三大组件。vector是自动扩容的数组map是键值对字典set是有序不重复集合sort和find是最常用的算法。模板和 STL 是 C 的精髓所在。掌握了它们你就迈入了用 C 高效编程的大门。下一节我们将继续深入探索更多 STL 容器和算法。加油