set中如何存儲自定義對象?
- 2020 年 3 月 11 日
- 筆記
如何在set中存儲自定義對象?
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做一下去重的事情,對於基本數據類型,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作為右操作數,調用比較函數,並返回比較值
- 將x作為左操作數,y作為右操作數,再調用一次比較函數,並返回比較值。 如果他們兩個都返回false,則認為重複,重複的元素不會被插入到容器中。
當然需要注意的是,如果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<了,那麼是不是只有這一種方法呢?