中小企业网站制作模板电子产品设计
2026/5/21 13:49:44 网站建设 项目流程
中小企业网站制作模板,电子产品设计,黄页88网推广服务,带用户中心的WordPress主题如果你在学 C STL#xff0c;可能会对 “仿函数”“适配器” 这两个词感到陌生 —— 明明有函数指针#xff0c;为啥要搞仿函数#xff1f;栈和队列看着像独立容器#xff0c;怎么又和 “适配器” 挂钩了#xff1f;其实这两个概念的核心特别简单#xff1a;仿函数是 “像…如果你在学 C STL可能会对 “仿函数”“适配器” 这两个词感到陌生 —— 明明有函数指针为啥要搞仿函数栈和队列看着像独立容器怎么又和 “适配器” 挂钩了其实这两个概念的核心特别简单仿函数是 “像函数的类”解决灵活比较的问题适配器是 “容器的转换器”解决代码复用的问题。今天咱们用大白话 实战代码把这两个知识点讲透新手也能轻松跟上一、仿函数让 “类” 像函数一样干活先想个场景你写了个堆调整函数AdjustDown需要比较父节点和子节点的大小。如果今天要 “小堆”父节点比子节点小明天要 “大堆”父节点比子节点大难道要写两个几乎一样的函数吗仿函数就是为解决这个问题而生的 —— 它用类封装比较逻辑但用起来和函数完全一样还能通过模板实现 “泛型比较”。1. 仿函数是什么本质是 “重载了 () 的类”仿函数也叫函数对象不是函数而是一个重载了operator()的类。这个类的对象可以像函数一样被调用比如com(a, b)本质是调用com.operator()(a, b)。举个最常用的例子文档里的less仿函数修正了原文档的语法错误加了详细注释cpp// 模板仿函数实现“小于”比较逻辑 template class T // T是泛型支持int、double等各种类型 class less { public: // 重载operator()接收两个const引用避免拷贝保证不修改参数 // 返回值是bool表示t1是否小于t2 bool operator()(const T t1, const T t2) const { return t1 t2; // 核心比较逻辑 } }; // 同理还能实现“大于”仿函数 template class T class greater { public: bool operator()(const T t1, const T t2) const { return t1 t2; } };关键特点用模板支持任意类型int、string、自定义类都能用比较逻辑封装在类里想换逻辑只换仿函数类型不用改核心代码比函数指针更安全编译期检查、更灵活可封装状态比如带比较阈值。2. 仿函数怎么用实战堆调整函数拿文档里的AdjustDown堆的向下调整举例看看仿函数如何替代 “硬编码比较”。原来的硬编码方式不灵活如果直接写_con[child] _con[child1]只能实现一种堆比如小堆要改大堆就得改代码cppvoid AdjustDown(int parent) { size_t child parent * 2 1; // 左孩子 while (child _con.size()) { // 硬编码“找更大的孩子”想找更小的就得改“”为“” if (child 1 _con.size() _con[child] _con[child 1]) { child; } // 硬编码“父节点小于孩子则交换” if (_con[parent] _con[child]) { swap(_con[parent], _con[child]); parent child; child parent * 2 1; } else { break; } } }用仿函数的灵活方式一键切换堆类型把比较逻辑交给仿函数核心代码不变换仿函数就换逻辑cpp// 给AdjustDown加仿函数模板参数Compare默认用less小堆 template class Compare lessint void AdjustDown(int parent) { size_t child parent * 2 1; Compare com; // 创建仿函数对象像“函数工具”一样用 while (child _con.size()) { // 用com(a,b)替代硬编码的“”比较逻辑由Compare决定 if (child 1 _con.size() com(_con[child], _con[child 1])) { child; // 找到“符合比较逻辑”的孩子less找大的greater找小的 } // 同样用com比较父和子 if (com(_con[parent], _con[child])) { swap(_con[parent], _con[child]); parent child; child parent * 2 1; } else { break; } } } // 调用示例 vectorint _con {3,1,2,4}; AdjustDownlessint(_con, 0); // 用less调小堆 AdjustDowngreaterint(_con, 0); // 用greater调大堆不用改核心代码3. 仿函数小结核心用类封装逻辑用对象模拟函数调用优势泛型支持、逻辑可换、编译安全常见场景STL 算法比如sort的第三个参数、容器底层堆、set/map 的比较。建议配一张图帮助理解![仿函数工作流程](这里建议插入一张流程图内容包括1. 定义 Compare 仿函数less/greater→ 2. 创建 com 对象 → 3. 调用 com (a,b) 触发 operator () → 4. 返回比较结果。用箭头连接标注每个步骤的作用。)二、适配器容器的 “电源转换器”核心是代码复用你家里的电源是 220V但手机充电需要 5V这时候就需要 “电源适配器”。C 里的适配器也是这个道理基于已有的容器比如 deque封装一层接口变成新的数据结构比如栈、队列不用重新写底层存储逻辑。文档里的栈和队列就是最典型的 “容器适配器”—— 它们的底层依赖deque双端队列自己只封装 “栈 / 队列专属接口”。1. 适配器是什么本质是 “接口封装 复用底层容器”适配器不自己实现存储而是 “借” 已有容器的底层结构比如 deque 的动态数组然后暴露符合自己特性的接口栈stack是 “后进先出”LIFO只需要 “尾插、尾删、取尾元素”所以复用 deque 的push_back、pop_back、back()队列queue是 “先进先出”FIFO只需要 “尾插、头删、取头 / 尾元素”所以复用 deque 的push_back、pop_front、front()、back()。这样做的好处不用重复写底层扩容、内存管理代码直接复用 deque 的成熟实现减少 bug。2. 实战代码用 deque 实现栈stack适配器下面是文档里的stack适配器代码修正了语法错误比如_con_con.size的笔误加了注释cpp#pragma once // 防止头文件重复包含 #include deque // 依赖deque作为底层容器 namespace practice { // 自定义命名空间避免和STL冲突 // 模板参数T是栈存储的元素类型Con是底层容器默认用dequeT template class T, class Con std::dequeT class stack { public: // 1. 压栈复用deque的push_back尾插 void push(const T x) { _con.push_back(x); } // 2. 出栈复用deque的pop_back尾删 void pop() { // 注意实际项目中应该先判断栈是否为空避免崩溃 if (empty()) { throw std::runtime_error(stack is empty!); } _con.pop_back(); } // 3. 获取栈顶元素复用deque的back()取尾元素 T top() { if (empty()) { throw std::runtime_error(stack is empty!); } return _con.back(); } // 4. 获取栈顶元素const版本供const对象调用 const T top() const { if (empty()) { throw std::runtime_error(stack is empty!); } return _con.back(); } // 5. 获取栈大小复用deque的size() size_t size() const { return _con.size(); } // 6. 判断栈是否为空复用deque的size() bool empty() const { return _con.empty(); // 比_con.size() 0更高效 } private: Con _con; // 底层容器对象所有操作都委托给它 }; }调用示例cpp#include my_stack.h #include iostream using namespace practice; int main() { stackint s; // 用默认底层容器dequeint s.push(1); s.push(2); s.push(3); std::cout 栈顶元素 s.top() std::endl; // 输出3 std::cout 栈大小 s.size() std::endl; // 输出3 s.pop(); // 出栈3 std::cout 出栈后栈顶 s.top() std::endl; // 输出2 return 0; }3. 实战代码用 deque 实现队列queue适配器和栈类似队列适配器复用 deque 的接口只暴露 “先进先出” 需要的功能修正文档语法错误后cpp#pragma once #include deque namespace practice { template class T, class Con std::dequeT class queue { public: // 1. 入队尾插复用deque的push_back void push(const T x) { _con.push_back(x); } // 2. 出队头删复用deque的pop_front void pop() { if (empty()) { throw std::runtime_error(queue is empty!); } _con.pop_front(); } // 3. 获取队头元素复用deque的front() T front() { if (empty()) { throw std::runtime_error(queue is empty!); } return _con.front(); } // 4. 获取队尾元素复用deque的back() T back() { if (empty()) { throw std::runtime_error(queue is empty!); } return _con.back(); } // 5. 队列大小和判空 size_t size() const { return _con.size(); } bool empty() const { return _con.empty(); } private: Con _con; // 底层容器委托所有操作 }; }调用示例cpp#include my_queue.h #include iostream using namespace practice; int main() { queueint q; q.push(10); q.push(20); q.push(30); std::cout 队头 q.front() 队尾 q.back() std::endl; // 10, 30 q.pop(); // 出队10 std::cout 出队后队头 q.front() std::endl; // 20 return 0; }4. 适配器小结核心“借鸡生蛋”复用已有容器的底层封装新接口常见适配器stack栈、queue队列、priority_queue优先队列底层是 vector灵活点可以指定底层容器比如stackint, vectorint s用 vector 做栈的底层。建议配一张图帮助理解![栈 / 队列适配器与 deque 的关系](这里建议插入一张对比图左侧是 stack 的接口push、pop、top右侧是 queue 的接口push、pop、front、back中间指向底层 deque 的对应接口push_back、pop_back、back、pop_front、front用箭头标注 “复用关系”比如 stack::push → deque::push_back。)三、总结仿函数与适配器的核心价值概念本质解决的问题典型场景仿函数重载 () 的类灵活切换比较 / 运算逻辑避免硬编码sort 排序、堆调整、set 比较适配器封装已有容器的接口复用底层代码快速实现新数据结构stack 栈、queue 队列简单来说想让 “比较逻辑可换”用仿函数想 “快速实现栈 / 队列”不用自己写底层用适配器。这两个概念是 STL 的设计精髓理解它们不仅能帮你用好 STL还能提升自己的 “代码复用” 和 “灵活设计” 能力。试着把上面的代码敲一遍感受一下仿函数的灵活和适配器的便捷吧如果有疑问欢迎在评论区留言讨论

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询