2012-11-23 198 views
118

我在某種程度上驚訝的是,下面的代碼編譯和運行(vc2012 & gcc4.7.2)爲什麼我可以在私人類型上使用自動?

class Foo { 
    struct Bar { int i; }; 
public: 
    Bar Baz() { return Bar(); } 
}; 

int main() { 
    Foo f; 
    // Foo::Bar b = f.Baz(); // error 
    auto b = f.Baz();   // ok 
    std::cout << b.i; 
} 

它是正確的,這個代碼編譯罰款?爲什麼它是正確的?爲什麼我可以在私人類型上使用auto,而我無法使用其名稱(如預期的那樣)?

+10

觀察到'f.Baz()i'也行,因爲是'的std :: cout << typeid(f.Baz())。name()'。如果你能掌握它,那麼類外的代碼就可以「看見」Baz()返回的類型,你不能命名它。 –

+2

如果你認爲這很奇怪(你可能會這樣做,當你問這個問題時你會看到),你並不是唯一一個;)這個策略對於[安全布爾成語](http:// www .artima.com/cppsource/safebool.html)。 –

+2

我認爲要記住的一點是'private'是爲了方便描述API而編譯器可以幫助執行的方式。它並不打算阻止'Foo'的用戶訪問'Bar'類型,因此它不會阻止'Foo'以任何方式通過返回'Bar'的實例來提供訪問。 –

回答

100

auto的規則大部分與模板類型扣除相同。你可以通過私有類型的對象模板函數一樣的道理的例子發佈的作品:

template <typename T> 
void fun(T t) {} 

int main() { 
    Foo f; 
    fun(f.Baz());   // ok 
} 

我們爲什麼可以通過私有類型的對象模板功能,你問?因爲只有類型的名稱是不可訪問的。類型本身仍然可用,這就是爲什麼你可以將它返回給客戶端代碼的原因。

+25

要查看* name *的隱私與* type *無關,請在問題中將'public:typedef Bar return_type_from_Baz;'添加到類'Foo'。現在,類型可以通過公開名稱來標識,儘管在類的私有部分中進行了定義。 –

+1

要重複@ Steve的觀點:_name_的訪問說明符與_type_無關,正如通過添加'private:typedef Bar return_type_from_Baz;'到'Foo'所看到的那樣[http://ideone.com/iKv2bQ)。 'typedef''d標識符無視訪問說明符,公開和私有。 – damienh

+0

這對我來說沒有意義。該類型的_name_僅僅是實際類型的別名。如果我稱之爲「Bar」或「SomeDeducedType」,有什麼關係?這不像我可以用它來獲得'Foo類'的私人成員或任何東西。 – einpoklum

98

訪問控制適用於名稱。從標準進行比較,以這個例子:

class A { 
    class B { }; 
public: 
    typedef B BB; 
}; 

void f() { 
    A::BB x; // OK, typedef name A::BB is public 
    A::B y; // access error, A::B is private 
} 
5

要添加其他(好)的答案,這裏是從C++ 98的例子,說明這個問題確實沒有在所有

auto
class Foo { 
    struct Bar { int i; }; 
public: 
    Bar Baz() { return Bar(); } 
    void Qaz(Bar) {} 
}; 

int main() { 
    Foo f; 
    f.Qaz(f.Baz()); // Ok 
    // Foo::Bar x = f.Baz(); 
    // f.Qaz(x); 
    // Error: error: ‘struct Foo::Bar’ is private 
} 

使用私人類型不被禁止,它只是命名的類型。例如,在C++的所有版本中創建該類型的未命名臨時文件都可以。

8

這個問題已被寒冷和R.馬丁尼費爾南德斯非常好的回答。

我只是不能放過這個機會,回答一個問題與哈利·波特的比喻:

class Wizard 
{ 
private: 
    class LordVoldemort 
    { 
     void avada_kedavra() 
     { 
      // scary stuff 
     } 
    }; 
public: 
    using HeWhoMustNotBeNamed = LordVoldemort; 
}; 

int main() 
{ 
    Wizard::HeWhoMustNotBeNamed tom; // OK 
    Wizard::LordVoldemort not_allowed; // Not OK 
    return 0; 
} 
+4

不是「哈利的朋友班」嗎? – Quentin

相關問題