C ++中的内部类是否自动成为朋友?


73

如果我在C ++中定义一个内部类,它是否自动成为包含它的类的朋友?例如,这合法吗:

class Outer {
public:
    class Inner {
    public:
        void mutateOuter(Outer& o);
    };

private:
    int value;
};

void Outer::Inner::mutateOuter(Outer& o) {
    o.value ++; // Legal?  Or not?
}

我问,因为在某些我尝试过的编译器(VS2003)上,此代码无法正常工作,但我至少听说过它在某些编译器上确实有效。我无法在C ++规范中找到与此相关的部分,并且如果有人可以引用某些特定的东西,那就说这是合法的或不合法的,那将是很好的。


嵌套类的成员函数遵循常规的访问规则,并没有特殊访问权限的封闭类:成员publib.boulder.ibm.com/infocenter/comphelp/v8v101/...
Anycorn

1
@ aaa-感谢您的链接,但这似乎仅适用于IBM的编译器,我知道它确实对规范具有一些自由(例如,允许您使用&&运算符来获取标签的地址)。抱歉,如果我一直坚持不懈,但是我教一门C ++编程课程,并且想在我对学生讲任何事情之前非常确定答案。
templatetypedef

我不这么认为,因为如果是这种情况,那么我们就无需在类体内也显式地声明好友类。在这种情况下,只需声明就足够了
mukeshkumar 2011年

@template AFAIK专门列出了非标准扩展名。
Anycorn

4
顺便说一句,问题不是“它是朋友吗”,而是“它是否具有私人访问权限”。(前者足够,但不是必须的。)
GManNickG 2011年

Answers:


76

我自己在这里或多或少地问了同样的问题之后,我想分享一下(显然)C ++ 11的更新答案:

引自https://stackoverflow.com/a/14759027/1984137

标准$ 11.7.1

“嵌套类是成员,因此具有与任何其他成员相同的访问权限。封闭类的成员对嵌套类的成员没有特殊的访问权限;应遵守通常的访问规则”

并且通常的访问规则指定:

“班级成员还可以访问班级可以访问的所有名称...”

标准中给出了具体示例:

class E {
    int x;
    class B { };

    class I {
        B b; // OK: E::I can access E::B
        int y;
        void f(E* p, int i) {
            p->x = i; // OK: E::I can access E::x
        }
    };
}

2
完全同意。我认为,应该对此问题的答案进行修订,因为问题中提出的代码现在可以正确编译。这是证明:链接
Givi 2013年

gcc 4.8.2有一个仅在gcc 4.9.0中修复的错误。gcc.gnu.org/bugzilla/show_bug.cgi?id=59482
Paulo Neves,

简而言之:C ++ 11及更高版本为“是”,而C ++ 03及更低版本为“否”。
Daniel Kiss

43

直到C ++ 11(即C ++ 98和C ++ 03)

在C ++ 98和C ++ 03中,默认情况下,嵌套类无法访问,private并且protected包含类的成员。

C ++ Standard(2003)在$ 11.8 / 1 [class.access.nest]中说,

嵌套类的成员无权访问封闭类的成员,也无权授予封闭类的类或函数;应遵守通常的访问规则(第11条)。封闭类的成员对嵌套类的成员没有特殊的访问权限。应遵守通常的访问规则(第11条)。

来自标准本身的示例:

class E 
{
    int x;
    class B { };
    class I 
    {
        B b; // error: E::B is private
        int y;
        void f(E* p, int i)
        {
           p->x = i; // error: E::x is private
        }
   };
   int g(I* p)
   {
       return p->y; // error: I::y is private
   }
};

从C ++ 11开始

自C ++ 11起,上述限制已被删除。现在,嵌套类可以访问封闭类的privateprotected成员:

class E 
{
    int x;
    class B { };
    class I 
    {
        B b; // ok: even though E::B is private
        int y;
        void f(E* p, int i)
        {
           p->x = i; // ok: even though E::x is private
        }
   };
   int g(I* p)
   {
       return p->y; // ok: even though I::y is private
   }
};

希望能有所帮助。


@templatetypedef:我知道嵌套类无法访问封闭类的私有成员,但是引用了错误的引用。无论如何,我更正了参考!
纳瓦兹

2
省略之后g(),代码从C ++ 11开始可以正常编译。应该更新答案。
iammilind

如果您使用有关C ++ 11的相关信息来更新答案,那将是很棒的,因为两者之间存在关键差异;)
Alexey 2015年

@Alexey:更新。
Nawaz

1
我尝试使用其默认编译器(LLVM 9.0)在xcode 9.2上编译此代码,但未编译。它在行return p-> y处失败。似乎可以访问父类的私有成员,但不能访问父类的子类的私有成员。
拉斐尔·萨比诺

16

由于发问者似乎已经接受了答案之一,因此这只是补充。
该标准似乎已更改了有关可访问性的规范。

C ++ 98中的第11.8 / 1条规定:

嵌套类的成员无权访问封闭类的成员,也无权授予封闭类的类或函数;应当遵守通常的访问规则。

N1804(TR1之后)中的第11.8 / 1条规定:

嵌套类是成员,因此具有与任何其他成员相同的访问权限。

我认为当前的C ++编译器遵循更新的规范。


2
嵌套类是成员,但是嵌套类成员可以视为封闭类的成员吗?这不是很明显。嵌套类本身(而不是其成员)可以访问封闭类的成员,如下所示:class Enclosing {private: enum PrivateEnum {VALUE}; class Nested {/*accessing enclosing class' member type*/ PrivateEnum e;}; };
谢尔盖·塔切诺夫

1
@SergeyTachenov:嗨。N1804中的第11.8 / 1节还指出:封闭类的成员对嵌套类的成员没有特殊访问权限应当遵守通常的访问规则。该语句从C ++ 98起没有变化。因此,对于从封闭类到嵌套类的访问(与templatetypedef问题相反),适用通常的访问规则。
伊势紫藤

@Ise,我不是在谈论对嵌套类成员的访问,这是一个完全不同的问题。我只是不确定“嵌套类是成员”概念是否也适用于嵌套类的成员。那几层嵌套呢?
Sergei Tachenov 2011年

@SergeyTachenov:对不起,我误解了您的评论。如果您是说class A { int i; class B { struct C { void f( A* x ) { x->i = 0; } }; }; };标准中是否允许,我想允许它是标准的意图。VC8,g ++ 3.4.5和Comeau在线允许。但是我不能说确定的话。如果您担心的话,建议将这个问题发布到StackOverflow中。比我更详细的知识的人会回答。
伊势紫藤

@Ise,很抱歉为您添加了无关紧要的内容。最初,我对N1804的引用进行了评论:“嵌套类是成员”-这是否意味着嵌套类的成员也是封闭类的成员?我的意思是,在class A {int i; class B {A *a; int f() {return a->i;} }; };B类中是A类的成员,但是B :: f()是A :: B类的成员,而不是A!但是我刚刚从DR 45中找到了另一条引语,它可以澄清这一点:“类的成员也可以访问所有名称,因为它是其成员所在的类。” 换句话说,B :: f()的类B的“继承”访问权限
谢尔盖Tachenov

4

该答案与(过时的)C ++ 03规范有关。在此问题上可接受的答案是最新的。

好吧,我现在问这个问题很可笑,因为我刚刚发现规范的相关部分涵盖了以下内容:§11.8/ 1:

嵌套类的成员无权访问封闭类的成员,也无权授予封闭类的类或函数;应遵守通常的访问规则(第11条)。封闭类的成员对嵌套类的成员没有特殊的访问权限。应遵守通常的访问规则(第11条)

(我的重点)

因此,似乎没有,内部类没有特殊的访问权限。


您对该段有误解。没有11.8.1,您是说11.8p1(或“ 11.8 / 1”)吗?
Fred Nurk 2011年

@Fred Nurk- Whoops,表示11.8 / 1。将修复。
templatetypedef

@Fred Nurk-另外,当您说我误解它时,是否表示我误解了它,或者只是误贴了标签?
templatetypedef

和@Fred:templatetypedef是正确的。请看我的帖子。我还引用了Standard本身的示例。
纳瓦兹

3

我并没有掌握确切的位置,但是我确实回想起通读规范,发现某个类中的任何私有数据对所有其他类(包括嵌套类)都是隐藏的。

基本上,嵌套类定义了某个范围,而不是访问权限。


1
您是错误的,但我只是-1,因为不知何故,即使附近引用了正确的答案,它也获得了+1。@投票者,请在投票前随意阅读所有答案。
GManNickG
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.