【问题标题】:Access to private nested class returned from member function访问从成员函数返回的私有嵌套类
【发布时间】:2015-10-18 11:43:48
【问题描述】:

请帮助我理解为什么类成员函数可以返回私有嵌套类对象,以及为什么可以在该私有嵌套类上调用成员函数,例如:

class Y
{
    class X
    {
    public:
        void f() { cout << "Hello World" << endl; }
    };

public:
    X g() { return X(); }
};

void h()
{
    Y::X x;     // Error, as expected: class Y::X is private.
    x.f();      // Error.

    Y y;        // OK.
    y.g().f();  // OK. But why???
}

我用 GCC 和 Visual C++ 进行了测试,最后一行在两者上都可以编译。我似乎在 C++ 标准中找不到任何可以使它有效的东西。任何想法为什么这有效?

编辑:

另一个观察:

void i()
{
    Y y;

    Y::X x2 = y.g(); // Error: class Y::X is private
    x2.f();          // Error

    auto x3 = y.g(); // OK
    x3.f();          // OK
}

【问题讨论】:

  • 这两个函数都是public,而你实际上并没有在任何地方使用X。
  • X 的定义是私有的,而函数g() 是公共的。所以完全没有问题。

标签: c++


【解决方案1】:

创建一个嵌套类private 并不意味着外部作用域永远不能使用该类的实例。访问说明符会影响 names,并且您的 main 函数永远不会尝试 name Y::X。1 唯一命名 Y::X 的地方在Y 内,当然可以访问自己的private 成员。该函数将Y::X 的实例返回到main 并不是特别相关。

[C++14: 11/1]:一个类的成员可以是

  • private;也就是说,它的name只能被声明它的类的成员和朋友使用。
  • protected;也就是说,它的名称只能由声明它的类的成员和朋友、从该类派生的类以及它们的朋友使用(参见 11.4)。
  • public;也就是说,它的名称可以在任何地方使用而不受访问限制。

诚然,该标准没有任何文本可以明确地让您感到困惑,并指出对实体本身的访问不受这些关键字的控制,但这绝对是意图,最终,就法律术语而言。

1 它确实命名为Y::X::f,但该名称是public。

【讨论】:

  • 现在我很好奇:在引入auto 之前,是否可以将g() 的结果存储在一个变量中?
  • @SvenMarnach:我不知道怎么做。
  • 有趣。我没有意识到auto 允许声明否则是不可能的。我一直认为auto主要是一个方便的功能。
  • @SvenMarnach:能够声明以前无法声明的内容非常方便。坦率地说,我认为这是导致auto 的可怕之处的严重不一致,但我们开始了。
【解决方案2】:

为什么类成员函数可以返回私有嵌套类对象

嵌套类也是类成员,成员函数对私有成员有访问权限。

以及为什么可以在该私有嵌套类上调用成员函数

您在这里没有使用私有嵌套类名,即Y::X。而Y::X::f()是一个公共函数,所以可以直接调用。

【讨论】:

    【解决方案3】:

    在这里您可以找到您正在寻找的示例。 f1 是公开的,f2 是私有的并会触发您所期望的错误:

    #include <iostream>
    
    class Y
    {
        class X
        {
            public:
                void f1() { std::cout << "Hello World" << std::endl; }
            private:
                void f2() { std::cout << "Hello World" << std::endl; }
        };
    
        public:
            X g() { return X(); }
    };
    
    int main()
    {
        // Y::X x;     // Error, as expected: class Y::X is private.
        // x.f();      // Error.
    
        Y y;         // OK.
        y.g().f1();  // OK. Because f1 is public.
        y.g().f2();  // Error. Because f2 is private.
    
        return 0;
    }
    

    【讨论】:

    • 我认为 OP 想知道为什么 y.g() 会起作用,就像其他任何事情一样...尤其是当他们竭尽全力表明我们实际上可以得到 Y::X 的实例时,只要我们避免命名它的类型,使用auto。
    • 也许吧。在这种情况下,我的答案可以被删除。让 OP 决定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    • 1970-01-01
    • 2015-04-01
    相关资源
    最近更新 更多