如何在set中存储自定义对象?
假设你已经在C++中使用过set,那么你应该知道,set中存储的元素是去重的。比如:
//来源:公众号:编程珠玑
//作者守望先生
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> a;
a.insert(123);
a.insert(111);
a.insert(111);
a.insert(2);
//遍历set
for(auto &it:a)
{
cout<<it<<endl;
}
return 0;
}
输出结果:
2
111
123
虽然插入了两次111,但是最终只会存储一个,也就是最后set中只有三个元素。
有时候,我们可能想通过set做一下去重的事情,对于基本数据类型,set都能很好地处理。我们看看对于自定义的对象,它的结果如何呢?
//来源:公众号【编程珠玑】
//作者:守望先生
#include <iostream>
#include <set>
using namespace std;
class MyObject
{
//方便起见,暂时设置为public
public:
int id;
string data;
public:
MyObject(int i,string d):id(i),data(d){}
};
int main()
{
set<MyObject> a;
a.insert(MyObject(123,"123"));
a.insert(MyObject(111,"111"));
a.insert(MyObject(111,"111"));
a.insert(MyObject(2,"2"));
for(auto &it:a)
{
cout<<it.id<<endl;
}
return 0;
}
很不幸,还没来得及运行,先报错了。
error: no match for ‘operator<’ (operand types are ‘const MyObject’ and ‘const MyObject’)
从报错信息我们可以推断出,它是需要调用‘operator<’,也就是说,我们需要重载操作符<,让它可以用来判断元素是否重复。那么重载它有什么原则呢? 关于操作符的重载,可以参考《什么是运算符的重载?》。
注意,这里是仅仅介绍去重时的原则,这里暂时未涉及排序。准则细看有很多,这里总结起来就是: 两个元素如果没有任何一个小于另外一个,则他们视为重复。 假设比较函数是f(x,y),那么当f(x,y)和f(y,x)都返回false的时候,认为他们是重复的。
其实,set容器在判定已有元素a和新插入元素b是否相等时,是这么做的:
当然需要注意的是,如果x<y为true,那么x>y应为false,所以这里应该避免两个都返回true,否则将会出现未知行为。
对于我们前面的例子来说,假设id重复,则认为对象是相同的,那么重载的<参考实现如下:
bool operator<(const MyObject &a) const
{
if(this->id == a.id)
{
return false;
}
else
{
return this->id > a.id;
}
}
添加之后,重新运行,就符合预期,可以对自定义对象去重啦!
对于自定义对象存储在set中,如果我们希望它按照我们指定的规则去重,就可能需要重载operator<了,那么是不是只有这一种方法呢?