2012-09-27 70 views
0

我有一個程序結構類同:非常函數使用常量性

class A { 
    private: 
     std::set<B> members; 
    public: 
     void func(const C& arg) { 
      std::set<B>::iterator iter = members.find(a); 
      if(iter != members.end()) { 
       iter->check(arg); 
      } 
     } 
} 



class B { 
    private: 
     std::deque<C> writers; 
    public: 
     void check(const C& arg) { 
      if(std::find(writers.begin(), writers.end, arg) != writers.end()) { 
       /* Code */ 
      } 
     } 
} 


class C { 
    private: 
     int id; 
    public: 
     bool operator==(const C& arg) { 
      return arg.id == this->id; 
     } 
} 

當我編譯,我得到以下錯誤消息:

no matching function for call to ‘B::check(const C&) const’ 
note: candidates are: void B::check(const C&) <near match> 

如果我宣佈check()const然後編譯器會拋出一個錯誤,要求將C類中的重載運算符==聲明爲const。我不知道是否讓const這個重載的操作符是正確的。 (我嘗試過一次,只要我能記得它也給了一些錯誤)。

我一直試圖解決這個問題超過五天,仍然沒有線索。

+3

好,使得運營商==常量可能引入了一些無關的錯誤,但它是正確的事情。平等測試不應該修改它們應用到的對象。所以,讓它成爲常量,並處理你遇到的任何其他問題。 –

+0

I _think_' set :: iterator'類型是'const',好像不是可以修改容器的'key',可能會破壞順序。因此''iter-> check(arg)'在一個'const B'實例上被調用,但是check()'不是''constst'因此錯誤。 – hmjd

回答

3

首先是operator==應該const。它不會修改數據,除非您想要混淆用戶,否則不應該修改數據。通常,每個不需要修改對象狀態的函數應該是const,以提供最大的靈活性(即允許通過常量引用進行調用)。

同樣可以應用於B::check,如果只測試而不修改,則應該是const。並且通過A::func的擴展,如果它不需要修改,那麼它應該是const。

錯誤信息在不同的編譯器中會略有不同。在你的情況下,編譯器執行重載決議並沒有找到一個匹配的號召是什麼抱怨:

沒有匹配函數調用「B ::檢查(常量ç&)常量」
注意:考生是:無效B ::檢查(常量ç&)

這表明它認爲你的成員,但丟棄它,因爲它需要與const標籤的成員函數。在其他編譯器中,錯誤消息將包含以下內容:調用void B::check(const C&)丟棄限定符這有點複雜,並且試圖說在const引用上調用非const成員函數將需要忽略const限定符。

+0

解釋他爲什麼也會遇到錯誤可能很好。 –

+0

這一個幫助;事實上,當我根據需要聲明瞭一個級聯的'const'時,原來的問題就解決了,並且與相同函數相關的新錯誤不是因爲const聲明。謝謝! – WeaklyTyped

3

您絕對應聲明B::check()C::operator==const,因爲它們不會更改對象狀態中的任何內容。

也可能不那麼明顯,但std::set<B>::iterator實際上是const_iterator(假設您使用C++ 11編譯器)!因此,您無法通過set迭代器調用B對象中的任何非const函數成員。

+0

在C++ 11中關於'iterator'是'const_iterator'的那一點真的如此嗎?這沒有意義,因爲只要不影響其嚴格排序,您應該可以對所需成員進行任何修改。設想一組僅包含單個成員作爲關鍵的複雜對象。 –

+0

@MarkRansom是的,的確如此,請參閱答案中的鏈接。它聲明迭代器是自C++ 11以來的常量迭代器。那麼,實際上它是有道理的,因爲它保證了容器數據排序不會被破壞。要有效地修改set中的對象而不對key產生影響,你可以將'erase'和'insert'與迭代器提示結合使用,在這種情況下插入將是恆定時間。 – Rost

+0

@MarkRansom這可能意味着'set'不是這樣的結構的最佳選擇... – Rost