2012-09-28 40 views
2

我正在使用C++的簡單散列表。我有方法來插入,刪除和搜索指定鍵的哈希表。我知道C++地圖STL容器可以處理我的情況,但我希望將自己的代碼編寫爲教育練習。已將[]散列表的運算符重載爲一個向量

基本上我有一個散列表,將採取一個單一的字符串,並將其映射到其他字符串的向量。這在一個方法中很容易實現,因爲調用.Add()或.Delete()將按預期行事。然而,我想創建一個重載的[]運算符到能夠在向量上執行這些操作的類。

例如,如果我想將項目添加到載體中我可以寫這樣的事:

 
    hashTable[string1] = newString; 

這將設置新的字符串作爲我的向量中的一員。刪除和搜索也可以這樣說。

 
    hashTable[string1] = ""; 
    cout << hashTable[string1] << endl; 

我的主要問題是,我不知道如何重載[]運營商獲得此功能。我現在編寫了這個函數。它適用於基本的1對1字符串匹配,但不適用於向量匹配的字符串。

 
    //Return a reference to a vector to update then reassign? 

     vector& HashClass::operator[](const string index) 
     { 
      assert(size >= 0 && size < maxSize); 
      Hash(key); 
      return hashTable[index];  
     } 

我想我最堅持有一個以後需要分配向量返回的想法。作爲用戶,我會找到這個kludgy。

+0

我個人不明白問題出在哪裏考慮a ...(也可以說是雖然) –

+0

你要2個不同的返回類型?一個重載的operator []返回一個字符串,另一個重載返回一個向量? – sashang

+0

從你寫的內容來看,你不清楚每個鍵是否有一個或多個字符串。 –

回答

0

在C++中,對關聯容器的訪問通常被賦予默認語義 - 構造映射類型的對象,使用鍵插入它,並返回對插入的映射對象的引用。

所以你operator[]將被實現爲:

string& HashClass::operator[](const string index) 
    { 
     assert(size >= 0 && size < maxSize); 
     Hash(key); 
     vector &v = hashTable[index];  
     if (index in v) { 
      ... 
     } else { 
      v.push_back(string()); 
      return v.back(); 
     } 
    } 
0

這個問題是密切相關的另一個問題:你 你想要的行爲,當您訪問不是在 分配等一個不存在的價值?換句話說,你想要什麼,當你寫的情況發生:

std::cout << hashTable[string] << std::endl; 

string是不存在的表?

有兩種可能的方法:您可以認爲它是一個錯誤,並且 會拋出異常或中止,或類似的;或者您可以返回 某種默認值,使用默認的構造函數構建,或者由客戶端提供的 。

標準映射和unordered_map採用第二種方法,使用默認構造函數 構造一個新值。這允許一個非常簡單的 解決方案:如果operator[]不存在,您插入它,用默認值初始化它 。然後您返回對它的引用; hashTable[string] = newString;通過對 的引用分配已經存在的值。

在許多使用情況,第一種方法將是最好(或許還有一個 contains功能,因此您可以測試前面的operator[] 是否會發現一些與否)。爲了實現第一種方法,你必須 首先實現每種類型的訪問的具體功能:

template <typename Key, typename Value> 
class HashTable 
{ 
public: 
    Value* get(Key const& key) const; 
    void set(Key const& key, Value const& value); 
}; 

(我一般讓這些公共的,沒有任何理由通過 禁止其使用的客戶端。)

然後,定義operator[]返回一個代理,具體如下:

template <typename Key, typename Value> 
class HashTable 
{ 
public: 
    class Proxy 
    { 
     HashTable* myOwner; 
     Key myKey; 
    public: 
     Proxy(HashTable* owner, Key const& key) 
      : myOwner(owner) 
      , myKey(key) 
     { 
     } 

     operator Value const&() const 
     { 
      Value const* result = myOwner->get(myKey); 
      if (result == NULL) { 
       // Desired error behavior here... 
      } 
      return *result; 
     } 

     Proxy const& operator==(Value const& value) const 
     { 
      myOwner->set(myKey, value); 
      return *this; 
     } 
    }; 

    Value* get(Key const& key) const; 
    void set(Key const& key, Value const& value); 

    Proxy operator[](Key const& key) 
    { 
     return Proxy(this, key); 
    } 
}; 

因此,當你寫:

hashTable[key] = newString; 

,代理的operator=將調用hashTable.put(key, newString);在其他情況下 ,但是,它會調用隱式類型轉換上 代理,這就要求hashTable.get(key)

在某些情況下,即使你渴望返回默認值,它可能是 最好使用此解決方案:get功能不需要 插入任何物件哈希表,因此該表不填寫了 所有失誤的,你可以在超載的constoperator[],所以 你可以用它在const哈希表也是如此。此外,它不需要 要求值類型具有默認構造函數。

它有相對於在標準 所使用的溶液中的一種缺點;因爲你不能超載operator.,你不能讓代理 表現得像一個參考,事情就是這樣:

hashTable[string].someFunction(); 

不起作用。一個解決辦法是在代理過載operator->,但 這導致有些不自然的語法:

hashTable[string]->someFunction(); // But the hash table contains 
            // values, not pointers!!! 

(不要被隱式轉換爲參考誤導的 隱式轉換不會在表達 a.b