2010-03-10 115 views
8

在下面的示例中(道歉的長度)我試圖隔離一些在私有繼承類中使用嵌套類時遇到的意外行爲。我經常看到一些聲明,說明與非內置類相比,嵌套類沒有什麼特別之處,但在本例中,可以看到一個嵌套類(至少根據GCC 4.4)可以看到一個嵌套類的公共類型定義類由閉幕類私下繼承。私有繼承的類型定義對嵌套類的可見性

我明白,typdefs與成員數據不一樣,但我發現這種行爲令人驚訝,我想其他許多人也會這樣。所以我的問題是雙重的:

  1. 是這種標準行爲? (一個體面的解釋爲什麼會很有幫助)
  2. 有人可以期望它適用於大多數現代編譯器(即它是多麼便攜)嗎?

#include <iostream> 

class Base { 
    typedef int priv_t; 
    priv_t priv; 
public: 
    typedef int pub_t; 
    pub_t pub; 
    Base() : priv(0), pub(1) {} 
}; 

class PubDerived : public Base { 
public: 
    // Not allowed since Base::priv is private 
    // void foo() {std::cout << priv << "\n";} 

    class Nested { 
    // Not allowed since Nested has no access to PubDerived member data 
    // void foo() {std::cout << pub << "\n";} 

    // Not allowed since typedef Base::priv_t is private 
    // void bar() {priv_t x=0; std::cout << x << "\n";} 
    }; 

}; 

class PrivDerived : private Base { 
public: 
    // Allowed since Base::pub is public 
    void foo() {std::cout << pub << "\n";} 

    class Nested { 
    public: 
    // Works (gcc 4.4 - see below) 
    void fred() {pub_t x=0; std::cout << x << "\n";} 
    }; 
}; 

int main() { 

    // Not allowed since typedef Base::priv_t private 
    // std::cout << PubDerived::priv_t(0) << "\n"; 

    // Allowed since typedef Base::pub_t is inaccessible 
    std::cout << PubDerived::pub_t(0) << "\n"; // Prints 0 

    // Not allowed since typedef Base::pub_t is inaccessible 
    //std::cout << PrivDerived::pub_t(0) << "\n"; 

    // Works (gcc 4.4) 
    PrivDerived::Nested o; 
    o.fred(); // Prints 0 
    return 0; 
} 
+1

歡迎來到StackOverflow! – fbrereto 2010-03-10 23:47:08

+2

試圖編輯「第一次在stackoverflow」評論,因爲問題是精美的問; – 2010-03-10 23:47:22

+0

熱烈的接待和偉大的答案。非常感謝。 – beldaz 2010-03-11 04:31:50

回答

4

前言:在下面的答案中,我指的是C++ 98和C++ 03之間的一些區別。然而,事實證明,我所談論的改變還沒有成爲標準,所以C++ 03在這方面與C++ 98沒有太大區別(感謝Johannes指出了這一點)。不知何故,我確信我在C++ 03中看到了它,但實際上它不在那裏。然而,這個問題確實存在(請參閱約翰內斯評論中的DR參考文獻),一些編譯器已經實現了他們認爲對該問題最合理的解決方案。所以,在下面的文本中對C++ 03的引用是不正確的。請將對C++ 03的引用解釋爲對某些編譯器已經試圖實現的此行爲的一些假設但很有可能的規範的引用。


重要的是要注意,在對C++ 98和C++ 03的標準之間的嵌套類訪問權限的顯著變化是很重要的。

在C++ 98嵌套類中,對封閉類的成員沒有特殊的訪問權限。它基本上是完全獨立的類,只是在封閉類的範圍內聲明。它只能訪問public封閉類的成員。

在C++中03嵌套類被給予訪問權限的封閉類的成員作爲成員的封閉類的。更確切地說,嵌套類被賦予了與封閉類的靜態成員函數相同的訪問權限。即現在嵌套類可以訪問任何封閉類的成員,包括私有的之一。

因此,您可能會觀察到不同編譯器和同一編譯器版本之間的差異,具體取決於他們何時實施新規範。

當然,你必須記住,嵌套類的一個對象不以任何方式綁定到封閉類的任何特定對象。就實際對象而言,這是兩個獨立的類。爲了從嵌套類訪問封閉類的非靜態數據成員或方法,您必須具有封閉類的特定對象。換句話說,再次嵌套類確實表現爲就像封閉類的靜態成員函數:它沒有具體的this指針封裝類,所以它不能訪問的非靜態成員除非你努力給它一個封閉類的特定對象來訪問。沒有它,嵌套類只能訪問封閉類的typedef名稱,枚舉和靜態成員。

一個簡單的例子,說明C++ 98和C++ 03之間的差異可能如下

class E { 
    enum Foo { A }; 
public: 
    enum Bar { B }; 

    class I { 
    Foo i; // OK in C++03, error in C++98 
    Bar j; // OK in C++03, OK in C++98 
    }; 
}; 

這種變化是什麼讓您的PrivDerived::Nested::fred功能進行編譯。它不會在編纂學C++ 98編譯器中通過編譯。

+0

*「C++ 89之間的區別」* - > *「C++ 98之間的區別」* – 2010-03-11 00:55:47

+0

@gf:已修復。謝謝。 – AnT 2010-03-11 00:59:54

+0

正是我之後,謝謝。我想我應該對我正在致力於確保與98標準兼容的代碼發出「使用」聲明。 – beldaz 2010-03-11 04:26:12

1

按照標準:

9.2 Class members

1 [...] Members of a class are data members, member functions (9.3), nested types, and enumerators. Data members and member functions are static or non-static; see 9.4.Nested types are classes (9.1, 9.7) and enumerations (7.2) defined in the class, and arbitrary types declared as members by use of a typedef declaration (7.1.3).

回答您的問題:

  1. Is this standard behaviour? (a decent explanation of why would be very helpful)

號至少與typedef不是被訪問。但是,請注意:

class Nested { 
    // Not allowed since Nested has no access to PubDerived member data 
    void foo() {std::cout << pub << "\n";} 

是有問題的。嵌套類既沒有PubDerived的實例,也沒有pub a static成員對象。

  1. Can one expect it to work on most modern compilers (i.e., how portable is it)?

是的。但請檢查文檔是否符合標準。並且始終:在嚴格模式下嘗試使用一些編譯器,例如Comeau。

+0

+1對PubDerived :: Nested :: foo()有很好的理解。關於指向標準的指針,我不清楚是否有任何提到的嵌套類可以看到(p00ya的答案發現了重要的條款,我認爲)。 – beldaz 2010-03-11 04:15:58

0

這並不回答你的問題,但根據我對the C++ FAQ Lite 24.6的看法,你試圖做的事是不允許的。我不確定gcc爲什麼允許它;你有沒有在其他編譯器中嘗試過它?

+0

只有GCC才能使用,這就是爲什麼我對代碼的可移植性感興趣。據我所知,鏈接的FAQ條目沒有提到嵌套類。 – beldaz 2010-03-11 04:02:25

1

我已經盡最大努力組裝ISO/IEC 14882:1997中的所有相關條款。

9.7節:

A class defined within another is called a nested class. The name of a nested class is local to its enclosing class. The nested class is in the scope of its enclosing class. Except by using explicit pointers, references, and object names, declarations in a nested class can use only type names, static members, and enumerators from the enclosing class.

11.2.1(應該是相當明顯):

[...] If a class is declared to be a base class for another class using the private access specifier, the public and protected members of the base class are accessible as private members of the derived class.

9.9嵌套類型名稱:

Type names obey exactly the same scope rules as other names.

然後在11.8:

The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (11) shall be obeyed. The members of an enclosing class have no special access to members of a nested class; the usual access rules (11) shall be obeyed.

從中我得出結論:您遇到的行爲是非標準的。嵌套類不應該有任何'特殊'訪問基地的私人成員。

然而,科莫C++,這似乎具有最好的標準支持,具有相同的行爲如GCC(允許fred,不允許bar與「錯誤:類型‘基礎:: priv_t’(第4行聲明)是不可訪問」 )。

+0

您提供的引用來自C++ 98規範。這是在C++ 03中重寫的,這就是爲什麼你會在Comeau中看到不同的行爲,以及更新版本的GCC和MSVC++編譯器。 – AnT 2010-03-11 00:20:10

+0

+1對標準的參考(AndreyT的評論也指出)。他們支持我直覺上期望的。 – beldaz 2010-03-11 04:10:13

+0

是啊我所說的沒有一個可以被假設爲適用於C++ 03(但我沒有該規範的副本不幸)。 – p00ya 2010-03-11 06:03:15

2

簡短的回答:嵌套類可以訪問C++ 0x中含有類私有成員,但不是C++ 1998年和C++ 2003。但是,對於C++ 98和C++ 2003編譯器,它是legal支持C++ 0x行爲,因爲舊行爲被視爲缺陷。

中規定的C++ 98和2003年的標準,部分11.8.1:

The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause 11) shall be obeyed. The members of an enclosing class have no special access to members of a nested class; the usual access rules (clause 11) shall be obeyed.

的C++ 0x部分11.8.1說:

A nested class is a member and as such has the same access rights as any other member. The members of an enclosing class have no special access to members of a nested class; the usual access rules (Clause 11) shall be obeyed.

Core Language Defect Report 45表明,原來的行爲是考慮到缺陷,所以非C++ 0x編譯器也可以支持新的行爲,儘管不是必需的。

+0

感謝您將答案添加到相對較舊的問題中。約翰內斯將你提到的DR與已接受的答案聯繫起來,但將它直接包含在答案中是很好的。從我+1。 – beldaz 2010-12-28 23:28:35