【问题标题】:Inner class, pimpl and a friend class - disagreeing compilers内部类,pimpl 和一个朋友类 - 不同意的编译器
【发布时间】:2024-04-12 15:00:02
【问题描述】:

我在一些旧的库代码中胡闹,基本目标是重构它。这段旧代码并不完全符合最佳实践和美感(是的 - 朋友很糟糕,并且在发现以下内容后已将其删除 - 因为它是重构中的疏忽)。

现在准备运行一些单元测试,我用 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;
}

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

-Wall -Wextra -pedantic

clang++ version: 3.3
g++ version:     4.8.2

现在 Visual C++ 抱怨 private_impl::say_world() 无法访问类 2 的私有成员。在查看 c++ 朋友规则后对我来说,这是正确的 - 但我对此的理解是错误的吗?我是否误读了信息(英语不是我的第一语言)?

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

嵌套类的成员对 封闭类,也不是授予友谊的类或函数 到封闭类;应遵守通常的访问规则(第 11 条)。 封闭类的成员对 嵌套类;应遵守通常的访问规则(第 11 条)。

还有这个:

友谊既不是遗传的也不是传递的。

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

另外 - 这个问题只是出于对此事的好奇,并试图更好地了解这个世界。

【问题讨论】:

  • 有趣的是,这在 C++11 中发生了变化:“嵌套类是一个成员,因此具有与任何其他成员相同的访问权限。”在下面的例子中,第一条评论是// OK: E::I can access E::B
  • 这已被归类为 C++03 中的缺陷,请参阅CWG 45,所以一切都是“正确的”! (至少,DR 是关于类似的东西,并且建议的解决方案也会影响您的情况。)g++ 和 clang++ 已经实现了针对缺陷的建议(并且在 C++11 中接受)解决方案,而 VC++2005 没有。
  • @dyp 感谢您提供的信息 - 我搜索了此信息,但结果为空(我的谷歌搜索技能似乎变弱了)。无论如何 - 有趣的是,使用 -std=c++03 使用 g++ 进行编译,上面的代码仍然有效 - 但猜测它已被视为标准中的缺陷,它是追溯实现的。发表您的评论作为答案,我会接受。
  • @dyp 作为答案发布,我没有机会循环引用 C++03 引用,否则我会更早发布答案 ;-)跨度>

标签: c++ inner-classes friend language-lawyer pimpl-idiom


【解决方案1】:

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

在C++11中,并入了解析,所以段落改成了[class.access.nest]/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
        }
    };

    int g(I* p) {
        return p->y;             // error: I::y is private
    }
};

——结束示例]

(某些)针对缺陷提出的解决方案在编译器中实现;注意g++ for example specifically says -std=c++03 标志的含义

1998 ISO C++ 标准加上 2003 技术勘误和一些额外的缺陷报告。

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


VC++2005 似乎没有按照原来的标准实现提议的解决方案。

【讨论】:

    最近更新 更多