2009-09-01 188 views
3

以下代碼不會編譯,並說「錯誤C2248:'A :: getMe':無法訪問類'A'中聲明的私有成員」。爲什麼?我正試圖調用公共接口。常量重載:C++類中的公共 - 專用查找

class B 
{ 
}; 

class A 
{ 
public: 
    const B& getMe() const; 
private: 
    B& getMe(); 
}; 

int main() 
{ 
A a; 
const B& b = a.getMe(); 
return 0; 
} 

回答

12

部分是可訪問性和可見性是獨立的概念在C++中。即使無法訪問,B& A::getMe()私有成員在main中也可見。所以在你的電話a.getMe()有兩個超負荷的成員要考慮,B& A::getMe()B const& A::getMe() const。由於a不是const它是被選中的私人成員。然後你會得到一個錯誤,因爲它不可訪問。如果你沒有私有的非const成員函數,你將只有const成員作爲唯一的可能性,並且它將被調用,因爲可以在非const對象上調用一個const成員。

請注意,如果可見性受限於可訪問性,您可能會遇到其他類型的混淆行爲:您重構一個成員,向該類之外的私人成員打電話。現在,私人會員不再可以訪問,所以這個電話是另一個公開的會員。這種沉默的行爲改變可能導致錯誤難以追蹤。總而言之:無論您的語言規則如何,決不會因不同的可訪問性而超載,這會導致混淆。

+0

「除了構造函數外,切勿使用不同的可訪問性重載」。擁有私有拷貝構造函數是完全合理的,即使在技術上重載了公共的默認構造函數。 – MSalters 2009-09-01 11:57:19

+0

@MSalters,當我將拷貝構造函數重載爲私有時,通常它是一個工作:我想壓制它,而不是重載它。作爲一個證明:我沒有提供一個實現:-)但是你關於構造函數的觀點是正確的:因爲你不能在不重載它們的情況下得到構造函數的某些效果,你有時別無選擇。至於所有一般規則,必然有例外;運營商提供的符號便利可能會導致其他人。一般來說,遵守發佈的界面可能讓你沒有更好的選擇。 – AProgrammer 2009-09-01 12:09:54

+0

+1爲優秀的解釋和建議! – sbi 2009-09-01 18:13:53

3

這是因爲要通過非const方法調用const方法,a應該是const以防止編譯器選擇非const方法。

爲了避免混淆具有相同名稱但具有不同訪問權限的兩個函數,將私有memeber函數稱爲其他函數會不會更容易。

+0

不正確:在非const對象上調用const方法是完全合法的(也是常見的)。在這種情況下,會出現混淆,因爲還有一個非const的私有版本的方法,編譯器決定(嘗試)調用該方法。 – 2009-09-01 10:30:47

+0

好主意:大概應該命名後綴爲_i – 2009-09-01 10:32:14

+0

@Martin B:這就是我的意思。答案現在已經澄清。感謝您的關注。 – Yacoby 2009-09-01 12:04:49

4

a在a.getMe()中不是const的,所以編譯器沒有意識到你正在嘗試使用該方法的const超載。

A const a; 
const B& b = a.getMe(); 

將按照您的預期工作(除了A需要初始化)。

8

在C++中,您不能在返回類型上重載。基於它們的常量重載成員函數也不例外:您重載調用函數的對象的常量,而不是返回類型。

要做到你想要的是一次在一個千載難逢的機會,利用const_cast添加常量性:

const B& b = const_cast<const A&>(a).getMe(); 

當然,雖然這是奇怪而有趣的,它可能是更容易閱讀如果你這樣做是這樣的:這是不是在其他的答案中提到的問題

const A& const_a = a; 
const B& b = const_a.getMe(); 
+0

我會對爲什麼會陷入低谷而感興趣。謹慎發表評論? – sbi 2009-09-03 13:22:06