内部类,pimpl和朋友类 - 不同意编译器

Arn*_*sen 6 c++ pimpl-idiom friend inner-classes language-lawyer

我在一些旧的库代码中捣乱,其基本目标是重构它.这个旧代码并不完全符合最佳实践和美观(是的 - 朋友很糟糕,并且在发现下面之后它已被删除 - 因为它是重构的疏忽).

现在准备运行一些单元测试我用clang ++,g ++和vc ++编译了代码(2005年 - 是的,我知道它已经过时了,但为了向后兼容 - 我必须这样做).

g ++和clang ++编译并运行没有错误,但Visual C++抱怨,所以在查看代码后,我发现了一些效果:

#include <iostream>

class one {

  private:
    struct private_impl;
    private_impl* pimpl_;

  public:
    one();
    ~one();
    void say_hello();
};

class two {

  private:
    friend class one;
    void say_world();

  public:

};

struct one::private_impl {
  two t;
  void say_world();
};

void one::private_impl::say_world() {
   std::cout << " ";
   t.say_world();  //This should not work should it?
}

one::one() : pimpl_(new private_impl) { }

one::~one() {
  delete pimpl_;
}

void one::say_hello() {
  std::cout << "Hello";
  pimpl_->say_world();
  std::cout << std::endl;
}

void two::say_world() {
  std::cout << "World";
}

int main() {
  one test;
  test.say_hello();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

用开关编译(g ++和clang ++):

-Wall -Wextra -pedantic

clang++ version: 3.3
g++ version:     4.8.2
Run Code Online (Sandbox Code Playgroud)

现在,Visual C++抱怨private_impl :: say_world()无法访问第二类的私有成员.在查看了c ++好友规则之后,对我来说,这是正确的 - 但是我对这个错误的理解是什么?我误读了这些信息(英语不是我的第一语言)?

从标准(c ++ 03 - 我现在手头没有c ++ 11):

嵌套类的成员对封闭类的成员没有特殊访问权限,也没有对已经为封闭类授予友谊的类或函数的特殊访问权限.应遵守通常的准入规则(第11条).封闭类的成员对嵌套类的成员没有特殊访问权限; 应遵守通常的准入规则(第11条).

而且这个:

友谊既不是遗传也不是传递.

所以我的基本问题是 - 谁真的是正确的 - clang和gcc还是vc ++?

此外 - 这个问题只是为了对此事的好奇心,并试图更好地了解这个世界.

dyp*_*dyp 2

周围类的成员的可访问性受CWG 45的影响。这意味着,至少部分问题已被归类为 C++98 标准中的缺陷。(似乎2001年就已经提出了解决方案,所以我不太明白为什么它还没有在C++03中修复。)

\n\n

在C++11中,合并了该决议,因此该段落已更改为[class.access.nest]/1:

\n\n
\n

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

\n\n
class E {\n    int x;\n    class B { };\n\n    class I {\n        B b;                     // OK: E::I can access E::B\n        int y;\n        void f(E* p, int i) {\n            p->x = i;            // OK: E::I can access E::x\n        }\n    };\n\n    int g(I* p) {\n        return p->y;             // error: I::y is private\n    }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x80\x94结束示例]

\n
\n\n

(一些)针对缺陷提出的解决方案在编译器中实现;例如,请注意g++ 明确表示该-std=c++03标志意味着

\n\n
\n

1998 年 ISO C++ 标准加上 2003 年技术勘误表和一些附加缺陷报告。

\n
\n\n

所以使用这个标志时你得到的结果并不明显。然而,DR 是“委员会意图的指示”,因此它们可以被视为标准中的“错误”,应该予以修复。

\n\n
\n\n

VC++2005 似乎没有按照原始标准实施建议的决议。

\n