2014-04-25 275 views
3

此代碼似乎工作,但我不知道爲什麼:嵌套類構造函數調用私有構造函數,它工作嗎?

#include <iostream> 

class Foo { 
    friend class Bar; 
public: 
    void printNum() {std::cout << num_ << "\n";} 
private: 
    // This constructor is private, should be accessible only to Bar 
    Foo(int num) : num_(num) {} 
    int num_; 
}; 

class Bar { 
public: 
    Bar(int num); 
    void printFooNum(); 
    ~Bar(); 
private: 
    class Impl_; 
    Impl_ * pImpl_; 
}; 

struct Bar::Impl_ { 
    Impl_(int num); 
    Foo foo_; 
}; 

Bar::Impl_::Impl_(int num) 
    : foo_(num) 
{} 

Bar::Bar(int num) 
    : pImpl_(new Impl_(num)) 
{} 

void Bar::printFooNum() { 
    pImpl_->foo_.printNum(); 
} 

Bar::~Bar() { delete pImpl_;} 

int main() { 
    Bar bar(5); 

    bar.printFooNum(); 

    return 0; 
} 

在這裏,我試圖確保Foo類的對象可以Bar類的對象,這是使用實現內部構造pImpl模式。我其實不介意構造函數Bar::Impl_()顯然能夠調用Foo構造函數,但我不確定爲什麼這應該起作用。這段代碼是使用幾種不同的編譯器(GCC和Intel)編譯的,它似乎給了我期望的結果,但我不確定這是因爲編譯器是寬容的還是代碼實際上是正確的。

爲什麼它似乎是Bar::Impl_()可以調用Foo構造函數時Foo只結識Bar而不是Bar::Impl_

回答

1

顯然,朋友班的所有成員都可以訪問宣佈爲朋友的班級的所有成員。由於嵌套的結構被視爲成員,因此嵌套的Bar可以訪問所有Foo的成員。在這裏看到:http://www.drdobbs.com/friendly-nesting/184401866

+0

我想我以前見過的多布斯博士的文章,我從中得到了外賣的是,你說的是隻在C++標準的後續版本真的,不是嚴格的C++ 98 。但是,嘿,如果編譯器對後來的標準支持足夠普及,我會接受。 – jjramsey

0

嵌套類具有相同的訪問權限的方法:他們有權訪問private部分包含類的,

class Outer { 
    struct Nested { 
     static void touch_private(Outer &x) { 
      x.private_member = 1; 
     } 
    }; 

    int private_member; 

    public: 
    Nested() { 
     Inner::touch_private(*this); 
    } 
}; 

...和外部類的朋友,這是像其隱私部分。 (插入笑話這裏。)

0

那麼,這是一個有趣的問題。但是,原因很簡單:嵌套類是其封閉類的成員。作爲成員,他們有權訪問封閉班級的所有其他成員及其所有朋友。 C++ 03標準狀態如此(§9.2/ 1(C++ 03))

1

朋友類的嵌套成員可以訪問授予友誼的私有和受保護成員的名稱。

C++標準n3337 11.3 § 2:

聲明一個類是朋友暗示的私有從類授予友誼的名稱和 保護成員可以訪問的基本符 和朋友的朋友聲明 類。 [例如:

class A {   // *your Foo 

    class B { }; // *private 

    friend class X; // *your Bar 

};

struct X : A::B { // OK: A::B accessible to friend 

    A::B mx;  // OK: A::B accessible to member of friend 

    class Y {  // *your Impl 

     A::B my; // OK: A::B accessible to nested member of friend 

    }; 
};