【问题标题】:C++ Outer class access Inner class's private - why forbiddenC++ 外部类访问内部类的私有 - 为什么被禁止
【发布时间】:2016-06-30 17:42:23
【问题描述】:

您好,我想知道为什么 C++ 标准允许我们在嵌套类中访问外部类的私有字段,而禁止从外部类访问内部类的私有字段。我明白,这个例子:

class OuterClass{
public:
    class InnerClass{
    public:
        void printOuterClass(OuterClass& outer) {cout << outer.m_dataToDisplay;};
    };
private:
    int m_dataToDisplay;
};

很好,因为内部类有时可能很复杂。但我认为以下情况也可以:

class Algorithm{
public:
    class AlgorithmResults{
    public:
        void readAlgorithmResult();
    private:
        void writeAlgorithmResult();
    };

    void calculate(AlgorithmResults& results, Arguments...){
       //calculate stuff
       results.writeAlgorithmResult(results);
    }
};

对我来说,这种结构非常有意义,尽管在 C++ 中是不允许的。我还注意到,有一段时间两者都在 Java 中被允许,但现在第二个例子也被禁止了。 是什么原因,第一个示例被允许而另一个示例被拒绝?

【问题讨论】:

    标签: c++ private


    【解决方案1】:

    本质上,within 之前在该范围内声明的范围名称是有效的并且可以直接使用(除非它们被遮蔽)。代码外部范围不能直接使用范围内声明的名称。例如。在花括号块之后的代码,不能直接使用在该块内声明的变量(间接使用的一个例子是外部代码可以访问指向花括号块内的静态变量的指针)。


    对于第二个示例,只需将 Algorithm 设为 friend of AlgorithmResults

    class AlgorithmResults
    {
        friend class Algorithm;
    

    【讨论】:

    • 对不起,我把友谊倒转了,不得不修复。这是另一个证明在发布到 SO 之前需要咖啡!
    • 我会 -1 这个答案,因为它似乎混淆了可用性与可访问性。我倾向于觉得一对花括号内的东西在那个范围之外是不可用的,而不是从那个范围之外严格来说是不可访问的。
    • @ComplYue:可访问性是标准的术语。不确定您所说的 UNAVAILABLE 与 INACCESSIBLE 是什么意思。也许我应该改写为“具有直接访问权限”,但从这条资格之路开始,必须将成员函数的返回类型的类型与类型名称区分开来,甚至可能更多——它很快就会变得模糊不清。
    • 我感觉UNAVAILABLE是因为目标已经不存在了,所以主题方没有办法到达它,尽管只有在目标仍然存在的情况下才允许访问;虽然 INACCESSIBLE 比不具有更多的存在意义,但临时限制禁止主体方接触目标。我希望我能让自己更清楚一点。
    • 我认为您对答案中的不完善术语有所了解。我不同意你的一般观点。作用域可以包含类型、静态变量和函数等等,它们不会随着执行移出作用域而停止存在;这不是一个动态的事情。但是,我选择的术语是不必要的错误。相关标准引用 C++2017:“通常,每个特定名称仅在程序文本的某些可能不连续的部分(称为其范围)内有效”。该标准讨论了名称在何处有效,以及名称是否可见。这很复杂。
    【解决方案2】:

    嵌套类可以访问外部类的私有字段,因为它是外部类的成员,与其他成员一样。

    [class.access.nest]/1

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

    另一方面,外部类对嵌套类没有特殊的访问权限,它们只是正常的关系。

    封闭类的成员对嵌套类的成员没有特殊的访问权限;应遵守通常的访问规则 ([class.access])。 [ 示例:

    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
      }
    };
    

    — 结束示例 ]

    【讨论】:

    • 这只是重复事实,但 OP 希望事实是合理的(尽管我认为这不是一个特别好的问题)。
    • @BarryTheHatchet 我试图从内部类到外部类、外部类到内部类的不同观点来解释它。不清楚?
    • 你解释得很好。我只是不认为这是 OP 所要求的。
    【解决方案3】:

    反问:你为什么要允许它?

    如果您需要外部类可以访问内部类的私有内部,您可以成为朋友:

        class Foo {
        public:
                class Frob {
                        friend class Foo;
                        int privateDataMember;
                };
    
                Foo () {
                        Frob frob;
                        frob.privateDataMember = 3735928559;
                }
        };
    

    C++ 没有可以解除好友关系的设备,因此允许对外部类的默认私有访问会窃取您的类设计工具并减少默认封装。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-02
      • 2011-02-17
      • 2017-05-31
      • 2016-08-04
      • 2014-08-10
      • 2013-09-20
      • 2021-01-05
      • 2017-01-16
      相关资源
      最近更新 更多