2014-04-25 281 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 

    }; 
};