【问题标题】:Given a class and its friend class, are the latter's inner classes automatically friends to the former class?给定一个类及其朋友类,后者的内部类是否自动成为前一类的朋友?
【发布时间】:2012-04-11 07:56:18
【问题描述】:

我正在尝试使用开源项目。最新的官方(来自 *.tar.gz 文件)和前沿(来自 SVN 存储库)版本都执行以下操作:

class Type1 {
    friend class Ridiculous;
    friend class Number;
    friend class Of_Friends;

    int  ImportantPrivateSemiSharedData;
};

 // In another header...

class Ridiculous {
    class Inner {
        void  MyFunc( Type1 &t )
        { /*do something with t.ImportantPrivateSemiSharedData*/ }
    };
};

AFAIK,将class A 标记为class Bfriend 确实 提供与A friendship 相关的任何类型B。从A 派生的类和friendly 和A 的类都不能得到friendship 和B。我认为这种限制也适用于内部类。

我使用的是 2002 年的计算机,它保留了几个操作系统版本,而该程序(可能是它的设计团队)主要在较新的计算机上。我的系统编译器只是旧的和破坏的,还是新热的编译器允许他们不应该做的事情?这是 C++11 的变化吗?

我只是想使用这个程序,但我一直卡在这样的事情上。我已经很怀疑了,因为代码中充满了诸如“拥有大量朋友的私人数据”和“无处不在的内部类”之类的技术,我认为这些都是代码异味。团队正在一起使用这些技术,但我认为它们从根本上是不兼容的,因为 friendship 不会继承,并且您不能前向声明内部类。

(如果需要,我正在使用 Mac OS X Tiger 10.4.11/PowerPC 32 位(配备 G4 的 eMac)。该程序是 LLVM 和 CLang(以及 LLVM 测试套件),尝试从 v3 .0 档案和来自 Subversion 的 r153311。编译器是 Apple 提供的 GCC 4.0.1 和 XCode 2.5。)

附录

看到第一个回复,现在我怀疑将班级标记为朋友有两种解释。给定一个包含friend class Xclass A,该声明可以授予对以下内容的访问权限:

  1. X 的成员函数(static 或特殊或两者都不是)。
  2. 任何函数,包括特殊函数,其完全限定名称具有 X 的完全限定名称作为前缀。

我认为我的编译器使用第一个定义,而作者的编译器使用第二个。是否有官方说法是正确的解释?如果是这样,规范是什么时候发生的(C++98/03,缺陷报告,C++11)?我一直认为友谊意味着第一个版本(包括我读过的 C++ 材料);直到现在,我才想到第二个。

【问题讨论】:

  • Type1 是我一段时间以来见过的最放荡的课程之一,让半个世界的人都搞砸了它的私人......不是评判,只是说。 :)
  • 如果您没有更新的计算机,您仍然可以使用 ideone.com 测试更新的编译器版本。
  • 关于附录,如果 A 类有一个朋友 X 类(即class A { friend class X; ... }; 那么 X 类的实例可以访问 A 类的私有成员。我认为你的两种解释(至少我的方式)读它们)有它倒着。正如你和我的例子所示,即使是 X 类的内部类也受益于 A 类与 X 类的友谊。你可以认为在类声明中添加一个朋友子句类似于在其上打开一个洞防火墙:A 类允许 X 类进入。ps 感谢您接受我的回答。:)

标签: c++ friend nested-class


【解决方案1】:

我认为这里有两个问题。一是代码闻起来很糟糕,正如你所说,二是它不能在你的系统上编译。关于气味,是的,过度使用 friend 关键字通常表明糟糕的 OO 设计。一般情况下,最好为对象提供完成其工作所需的东西,而不是从中提取一些东西,这基本上是friend 让你做的事情。

大量的内部类,IMO,并没有那么糟糕,因为它们只是用来将类保持在另一个范围内。这有助于保持命名空间不那么混乱,并允许您在不同的功能区域中使用通用名称。

关于编译问题,我尝试在我的系统(Ubuntu 10.04,gcc 4.4.3,此时已有两年)上重现此问题,并创建了此示例程序:

class A
{
    friend class B;

    int x;
};

class B
{
    class Inner
    {
    public:
        void foo(A& a)
        {
            a.x++;
        }
    };

public:
    void bbb()
    {
        Inner i;
        A a;

        i.foo(a);
    }
};

int main()
{
    B b;

    b.bbb();
}

编译时没有错误或警告。我最初没有任何标记为公共的,但我需要添加bbb() 来创建类Inner 的实例,并且我必须添加Inner 的公共方法以便我可以调用它来使用A 执行某些操作.

结果是我认为你的开发系统已经过时了。主要的开发人员在编译他们的代码时显然没有问题,所以区别在于你的系统,或者他们以一种他们没有告诉你的方式配置了他们的系统。话虽如此,我认为他们可以做更多的事情来使他们的代码更便携和更容易构建。在开源项目中,如果您希望其他人做出贡献,这是可以预料的。

【讨论】:

  • 代码是否总是应该是合法的,或者它是在 C++11 中添加的还是缺陷报告? (我说后者是因为我怀疑现在是否有任何系统编译器需要 C++11。而早期的编译器没有 C++11 模式。)我认为他们使用 GCC 作为引导编译器,也许他们(和你)正在利用 GCC 特定的怪癖/扩展。之前的规则已经改变:(基于另一个 SO 查询)C++11 现在使内部类成为其周围类的朋友;他们不是以前的。
  • @CTMacUser:代码是非法的,我不记得它被改变了,但事实是它已经在新标准中被改变了。 c++11 标准中有一个明确的例子说明了这一点。
  • 我不认为这是 C++11 的特性。正如我所说,我的编译器是 gcc 4.4.3,即from 2010 年 1 月。您的编译器 gcc 4.0.1 是从 2005 年 7 月开始的,所以很旧,很容易出现此代码的问题。您提出了一个很好的观点,即 gcc 会不时更改,但我更喜欢新版本而不是更旧的版本,尤其是与主要版本如此接近的版本(4.0.1 接近 4.0,并且可能有很多问题不是在发布时已知)。
猜你喜欢
  • 2017-01-17
  • 1970-01-01
  • 2011-06-28
  • 2012-05-15
  • 2012-05-19
  • 1970-01-01
  • 1970-01-01
  • 2019-08-26
  • 1970-01-01
相关资源
最近更新 更多