以下代碼不會編譯,並說「錯誤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;
}
以下代碼不會編譯,並說「錯誤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;
}
部分是可訪問性和可見性是獨立的概念在C++中。即使無法訪問,B& A::getMe()
私有成員在main
中也可見。所以在你的電話a.getMe()
有兩個超負荷的成員要考慮,B& A::getMe()
和B const& A::getMe() const
。由於a
不是const
它是被選中的私人成員。然後你會得到一個錯誤,因爲它不可訪問。如果你沒有私有的非const成員函數,你將只有const成員作爲唯一的可能性,並且它將被調用,因爲可以在非const對象上調用一個const成員。
請注意,如果可見性受限於可訪問性,您可能會遇到其他類型的混淆行爲:您重構一個成員,向該類之外的私人成員打電話。現在,私人會員不再可以訪問,所以這個電話是另一個公開的會員。這種沉默的行爲改變可能導致錯誤難以追蹤。總而言之:無論您的語言規則如何,決不會因不同的可訪問性而超載,這會導致混淆。
這是因爲要通過非const方法調用const方法,a應該是const以防止編譯器選擇非const方法。
爲了避免混淆具有相同名稱但具有不同訪問權限的兩個函數,將私有memeber函數稱爲其他函數會不會更容易。
不正確:在非const對象上調用const方法是完全合法的(也是常見的)。在這種情況下,會出現混淆,因爲還有一個非const的私有版本的方法,編譯器決定(嘗試)調用該方法。 – 2009-09-01 10:30:47
好主意:大概應該命名後綴爲_i – 2009-09-01 10:32:14
@Martin B:這就是我的意思。答案現在已經澄清。感謝您的關注。 – Yacoby 2009-09-01 12:04:49
a在a.getMe()中不是const的,所以編譯器沒有意識到你正在嘗試使用該方法的const超載。
A const a;
const B& b = a.getMe();
將按照您的預期工作(除了A需要初始化)。
在C++中,您不能在返回類型上重載。基於它們的常量重載成員函數也不例外:您重載調用函數的對象的常量,而不是返回類型。
要做到你想要的是一次在一個千載難逢的機會,利用const_cast
到添加常量性:
const B& b = const_cast<const A&>(a).getMe();
當然,雖然這是奇怪而有趣的,它可能是更容易閱讀如果你這樣做是這樣的:這是不是在其他的答案中提到的問題
const A& const_a = a;
const B& b = const_a.getMe();
我會對爲什麼會陷入低谷而感興趣。謹慎發表評論? – sbi 2009-09-03 13:22:06
「除了構造函數外,切勿使用不同的可訪問性重載」。擁有私有拷貝構造函數是完全合理的,即使在技術上重載了公共的默認構造函數。 – MSalters 2009-09-01 11:57:19
@MSalters,當我將拷貝構造函數重載爲私有時,通常它是一個工作:我想壓制它,而不是重載它。作爲一個證明:我沒有提供一個實現:-)但是你關於構造函數的觀點是正確的:因爲你不能在不重載它們的情況下得到構造函數的某些效果,你有時別無選擇。至於所有一般規則,必然有例外;運營商提供的符號便利可能會導致其他人。一般來說,遵守發佈的界面可能讓你沒有更好的選擇。 – AProgrammer 2009-09-01 12:09:54
+1爲優秀的解釋和建議! – sbi 2009-09-01 18:13:53