8

我有一個類,它看起來是這樣的:麻煩與常量/非const重載

class ClassA 
{ 
    public: 
    float Get(int num) const; 
    protected: 
    float& Get(int num); 
} 

類之外,我調用get()函數。

float foo = classAInstance.Get(i); 

我希望這個叫公版,而是Visual Studio中出現了錯誤:

error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA' 

當註釋掉保護過載和刪除所有引用的代碼編譯。

爲什麼編譯器會在可訪問的成員可用時嘗試使用不可訪問的成員?有沒有一種可以接受的方式來強制編譯器選擇正確的重載?是否有對成員函數解析規則的引用?

回答

7

確實如此,重載決議發生在可訪問性檢查之前。標準([over.match])的第13.3節說:

重載決策是選擇最佳功能的機制來調用因爲是 是調用的參數和一組候選函數表達式的列表可以根據 的調用情況調用。最佳函數的選擇標準是參數的個數,參數 與候選函數的參數類型列表匹配的程度,對於非靜態成員函數,對象與隱式對象參數匹配程度如何,以及候選函數的某些其他屬性。 [注意: 重載解析選擇的函數不保證適合上下文。其他 限制,如功能的可訪問性,可以使其在調用環境中使用不合格。 - 尾註]

通常的修復方法是給公共和受保護的函數使用不同的名稱。


注意,這有時是有用的,例如:

class Blah 
{ 
    const std::string& name_ref; 

    Blah(const char*) = delete; 

public: 
    Blah(const std::string& name) : name_ref(name) {} 

    void do_something_with_name_ref() const; 
}; 

std::string s = "Blam"; 
Blah b(s); // ok 

注意name_ref只會被讀取,所以這是適當的,使其const。但const引用可以綁定到臨時對象,並將name_ref綁定到臨時對象將是一個懸掛引用,導致do_something_with_name_ref()中的未定義行爲。

Blah c("Kablooey!"); // would be undefined behavior 
        // the constructor overload makes this a compile error 

私有構造函數重載可防止臨時std::string被隱式構造和綁定。

+0

這個例子看起來很危險。給定'string func();'和'Blah b(func())'的表達式將會被編譯,並且仍然會導致一個懸掛引用。我的規則是:*從不*保留'const&'參數。你說什麼? – 2014-03-07 08:01:05

+0

@MartinBa:當然你也希望'Blah(string &&)= delete;' – 2014-03-07 14:08:27

+0

嗯。然後問題就變成了是否仍然需要'const char'overload。 'char *'參數會綁定到'string const&'版本還是'string &&'版本? :-) – 2014-03-07 14:18:36

5

重載解析首先完成,然後訪問檢查。

如果你有一個const和一個非常量重載,這可以通過函數被調用的對象的常量來解決。