舉個例子,假設有如下一個 Person 類:關於什麼函數物件類,可閱讀《C++函數物件詳解》一節做詳細了解,由於不是本節重點,這裡不再贅述。
class Person { public: Person(string name, int age) :name(name), age(age) {}; string getName() const; int getAge() const; private: string name; int age; }; string Person::getName() const { return this->name; } int Person::getAge() const { return this->age; }在此基礎上,假設我們想建立一個可儲存 Person 類物件的 unordered_set 容器,考慮到 Person 為自定義的型別,因此預設的 hash<key> 雜湊函數不再適用,這時就需要以函數物件類的方式自定義一個雜湊函數。比如:
class hash_fun { public: int operator()(const Person &A) const { return A.getAge(); } };
可以看到,我們利用 hash_fun 函數物件類的 ( ) 運算子過載方法,自定義了適用於 Person 類物件的雜湊函數。該雜湊函數每接收一個 Person 類物件,都會返回該物件的 age 成員變數的值。注意,過載 ( ) 運算子時,其引數必須為 const 型別,且該方法也必須用 const 修飾。
由此,在建立儲存 Person 類物件的 unordered_set 容器時,可以將 hash_fun 作為引數傳遞給該容器模板類中的 Pred 引數:事實上,預設的 hash<key> 雜湊函數,其底層也是以函數物件類的形式實現的。
std::unordered_set<Person, hash_fun> myset;但是,此時建立的 myset 容器還無法使用,因為該容器使用的是預設的 std::equal_to<key> 比較規則,但此規則並不適用於該容器。
template<class T> class equal_to { public: bool operator()(const T& _Left, const T& _Right) const{ return (_Left == _Right); } };可以看到,該規則在底層實現過程中,直接用 == 運算子比較容器中任意 2 個元素是否相等,這意味著,如果容器中儲存的元素型別,支援直接用 == 運算子比較是否相等,則該容器可以使用預設的 std::equal_to<key> 比較規則;反之,就不可以使用。
bool operator==(const Person &A, const Person &B) { return (A.getAge() == B.getAge()); }
可以看到,通過此方式過載的運算子,當 std::equal_to<key> 函數物件類中直接比較 2 個 Person 類物件時,實際上是在比較這 2 個物件的 age 成員變數是否相等。換句話說,此時的 std::equal_to<key> 規則的含義為:只要 2 個 Person物件的 age 成員變數相等,就認為這 2 個 Person 物件是相等的。注意,這裡在過載 == 運算子時,2 個引數必須用 const 修飾。
std::unordered_set<Person, hash_fun> myset{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} };注意,雖然這裡給 myset 容器初始化了 4 個 Person 物件,但由於比較規則以各個類物件的 age 值為準,myset 容器會認為前 3 個 Person 物件是相等的,因此最終 myset 容器只會儲存 {"zhangsan", 40} 和 {"lisi", 30}。
class mycmp { public: bool operator()(const Person &A, const Person &B) const { return (A.getName() == B.getName()) && (A.getAge() == B.getAge()); } };在 mycmp 規則的基礎上,我們可以像如下這樣建立 myset 容器:
std::unordered_set<Person, hash_fun, mycmp> myset{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} };由此建立的 myset 容器,雖然初始化了 4 個 Person 物件,但 myset 容器根據 mycmp 比較規則,可以識別出前 2 個是相等的,因此最終該容器內部存有 {"zhangsan", 40}、{"lisi", 40} 和 {"lisi", 30} 這 3 個 Person 物件。
#include <iostream> #include <string> #include <unordered_set> using namespace std; class Person { public: Person(string name, int age) :name(name), age(age) {}; string getName() const; int getAge() const; private: string name; int age; }; string Person::getName() const { return this->name; } int Person::getAge() const { return this->age; } //自定義雜湊函數 class hash_fun { public: int operator()(const Person &A) const { return A.getAge(); } }; //過載 == 運算子,myset 可以繼續使用預設的 equal_to<key> 規則 bool operator==(const Person &A, const Person &B) { return (A.getAge() == B.getAge()); } //完全自定義比較規則,棄用 equal_to<key> class mycmp { public: bool operator()(const Person &A, const Person &B) const { return (A.getName() == B.getName()) && (A.getAge() == B.getAge()); } }; int main() { //使用自定義的 hash_fun 雜湊函數,比較規則仍選擇預設的 equal_to<key>,前提是必須過載 == 運算子 std::unordered_set<Person, hash_fun> myset1{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} }; //使用自定義的 hash_fun 雜湊函數,以及自定義的 mycmp 比較規則 std::unordered_set<Person, hash_fun, mycmp> myset2{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} }; cout << "myset1:" << endl; for (auto iter = myset1.begin(); iter != myset1.end(); ++iter) { cout << iter->getName() << " " << iter->getAge() << endl; } cout << "myset2:" << endl; for (auto iter = myset2.begin(); iter != myset2.end(); ++iter) { cout << iter->getName() << " " << iter->getAge() << endl; } return 0; }程式執行結果為:
myset1:
zhangsan 40
lisi 30
myset2:
lisi 40
zhangsan 40
lisi 30