2016-07-13 103 views
2

這是我在文件source.cpp代碼:基類的friend類如何通過派生於基類的類的對象訪問該基類的成員?

class B 
{ 
    friend class F; 
protected: 
    int protectedIntB; 
}; 

class D : public B {}; 

class F 
{ 
public: 
    int f(D &d) {return ++d.protectedIntB;} 
}; 

當我編譯以上g++ -c -Wall -pedantic -std=c++11 source.cppcl /c source.cpp碼,兩種編譯器編譯成功。然而,當我做d使用protected代替public的B繼承:

class D : protected B {}; 

這一次,GCC編譯成功,而CL給出了一個錯誤說B::protectedIntBreturn ++d.protectedIntB;無法訪問。

另一種情況是用private更換public

class D : private B {}; 

這一次,無論是編譯器產生的錯誤。順便說一下,我使用的是由VS2015的mingw-w64和cl版本19.00.24210構建的gcc版本5.3.0。

這裏我的問題是:

如何友元類是基類的基類成員的訪問,通過從基類派生的類的對象,爲什麼gcc和CL處理不同的看法?

編輯:

感謝songyuanyaoBrian,似乎在GCC 5.3.0在protected情況下的錯誤。只有public的情況下應該編譯成功,並且gcc 6.1.0也可以正常工作。

回答

3

根據[class.access.base]/5:

到成員的訪問是由該成員被命名爲類影響 。這個命名類是查找和發現成員名稱爲 的類。

根據[class.access.base]/6:

如果一個類的成員訪問運算符,包括隱式「this->」,用於訪問一個非靜態數據成員 或非靜態成員函數,如果左操作數(在 「.」運算符情況下被視爲指針)無法隱式轉換爲指向右操作數的命名類的指針,則該引用不合格。

因此,在您的特定情況下,爲了訪問d.protectedIntB,兩個以下必須爲真:

  • 你必須有訪問protectedIntB作爲B一員,因爲B是發現名稱爲protectedIntB的班級。 (注意:這可以通過使用using聲明在派生類重新聲明的構件改變;在這種情況下,派生類將被控制。)

  • 你必須有訪問B作爲鹼D,能夠將D*轉換爲B*。如果BD的公共基礎,那麼罰款。如果BD受保護基地,訪問檢查適用,這F::f失敗,因爲F不是D的朋友,而不是派生類的D

令人驚訝,似乎是GCC編譯器這是錯誤的受保護的情況下,但是這個bug appears fixed。請注意,Clang給出了一個much better diagnostic

0

如果代碼在gcc 5.3.0上編譯並且不在cl上編譯,那麼其中一個嚴格執行C++標準的概率很高。如果我必須猜測,對於受保護和私有繼承,您應該得到一個編譯器錯誤。有關更多詳細信息,請參閱Difference between private, public, and protected inheritance以瞭解不同種類的繼承之間的差異。

對於類F能夠訪問類B的私有成員,它應該知道類D從類B派生,這隻會發生公共繼承。

3

如果您使0123¾繼承自B使用受保護或私有而不是公共,編譯應該失敗。

從標準,$11.2/5 Accessibility of base classes and base class members [class.access.base]

當在N級命名爲A構件m是在點R可訪問如果

(5.4)存在的N基B類可訪問在當在B類命名爲R,並且 m是在r訪問[實施例:

class B; 
class A { 
private: 
    int i; 
    friend void f(B*); 
}; 
class B : public A { }; 
void f(B* p) { 
    p->i = 1;   // OK: B* can be implicitly converted to A*, 
        // and f has access to i in A 
} 

- 端示例]

對於您的第一種情況,的基類B可通過F::f()訪問,因爲它是公共繼承。並且B::protectedIntB可在F::f()訪問,因爲它是B類的朋友。

如果將其更改爲受保護或私有繼承,則D的基類B不能在F::f()處再次訪問,則編譯應該失敗。注F::f()不是派生類D的朋友。這意味着如果你也成爲類D的朋友,編譯將會成功。

順便說一句:我試着用gcc here保護繼承,它失敗了。

相關問題