【C++】C++ STL探索:Priority Queue与仿函数的深入解析(一)https://developer.aliyun.com/article/1617382
2.3 仿函数相较于普通函数优势
虽然普通函数在大多数情况下足够,但仿函数提供了更强大的功能和灵活性。
仿函数的优势
- 仿函数是模板编程的重要组成部分,可以与模板一起使用,实现泛型编程的目的。
- 将逻辑和数据封装在一个类中,并且可以轻松调整或扩展仿函数的行为,而不需要改变其调用接口
- 仿函数可以将复杂逻辑和数据封装在类对象中,使得代码更加模块化和可维护,重点体现在封装。
- 仿函数可以有成员变量,在不同的调用之间保持状态。
- 每个仿函数都有不同的类去封装,也可以更好适应泛型编程,灵活地去调整
通过一个类来控制这里的比较逻辑,并且内置类型与自定义类型都支持这种做法。
2.4 当T为指针类型
class Date { public: friend ostream& operator<<(ostream& _cout, const Date& d); Date(int year = 1900, int month = 1, int day = 1) : _year(year) , _month(month) , _day(day) {} bool operator<(const Date& d)const { return (_year < d._year) || (_year == d._year && _month < d._month) || (_year == d._year && _month == d._month && _day < d._day); } bool operator>(const Date& d)const { return (_year > d._year) || (_year == d._year && _month > d._month) || (_year == d._year && _month == d._month && _day > d._day); } private: int _year; int _month; int _day; }; ostream& operator<<(ostream& _cout, const Date& d) { _cout << d._year << "-" << d._month << "-" << d._day; return _cout; }
int main() { priority_queue <Date*, vector<Date*>, greater<Date*>> pqptr; pqptr.push(new Date(2024, 4, 14)); pqptr.push(new Date(2024, 4, 11)); pqptr.push(new Date(2024, 4, 15)); while (!pqptr.empty()) { cout << *(pqptr.top()) << " "; pqptr.pop(); } cout << endl; return 0; }
结果说明:正如图中问题,多次运行出现的结果是不同的,导致这种情况的原因是因为地址的大小new出来是随机的,这里如果是单纯的比较大小,只是比较地址编号的大小,而不是比较日期的大小。这里没有对*进行重载,对此需要单独写。
解决措施:
class GteaterDate { public: bool operator()(const Date* p1, const Date* p2) { return *p1 > *p2; } };
在类名实现比较指针的可调用函数对象(仿函数控制比较逻辑,控制任何比较)在优先级队列参数部分传递。
2.5 仿函数解决实际问题
场景如下:
假如我这里有一堆商品,我需要某个商品的排序,但是这里对于实际中需要排序的类型不止一种,那么如果需要看不同类型的排序,就需要修改,如何破局只有大于或者小于,但是总不能说"请稍等,程序员正在改代码"吧!对此需要使用仿函数的配合,模板帮我们控制的是类型不同的类型。
struct Goods { string _name; // 名字 double _price; // 价格 int _evaluate; // 评价 Goods(const char* str, double price, int evaluate) :_name(str) , _price(price) , _evaluate(evaluate) {} }; struct ComparePriceLess { bool operator()(const Goods& gl, const Goods& gr) { return gl._price < gr._price; } }; struct ComparePriceGreater { bool operator()(const Goods& gl, const Goods& gr) { return gl._price > gr._price; } }; struct CompareEvaluateLess { bool operator()(const Goods& gl, const Goods& gr) { return gl._evaluate < gr._evaluate; } }; struct CompareEvaluateGreater { bool operator()(const Goods& gl, const Goods& gr) { return gl._evaluate > gr._evaluate; } }; int main() { vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } }; sort(v.begin(), v.end(), ComparePriceLess()); sort(v.begin(), v.end(), ComparePriceGreater()); sort(v.begin(), v.end(), CompareEvaluateLess()); sort(v.begin(), v.end(), CompareEvaluateGreater()); }
注意:有些容器是没有迭代器的,这样子话就会破坏某种特性,一般不提供
三、反向迭代器
反向迭代器本质是写一个反向迭代器的类模板,给编译器传不同的容器的正向迭代器实例化,编译器帮助我们实例化出各种容器的对应反向迭代器。
3.1 反向与正向迭代器不同点
从功能上是类似的,但是运算符重载++与–运算符行为相反的。
同时反向与迭代器起始位置和结束位置是相反的,库里面也是形成对称,但是不是绝对的,如果满足反向迭代器逻辑就行。
思考:
这里it.rbegin()指向的位置(it.end)是哨兵位的位置,我们不希望访问到哨兵位的位置
解决办法:
需要注意:
这里++不是正向迭代器++运算符重载的逻辑,而是–的逻辑,因为是反向迭代器。这里是不支持tmp-1的,tmp是自定义类型,而没有-的运算符重载。
【C++】C++ STL探索:Priority Queue与仿函数的深入解析(三)https://developer.aliyun.com/article/1617384