【问题标题】:Accessing private nested class访问私有嵌套类
【发布时间】:2015-12-13 13:36:41
【问题描述】:

我做了这个简单的课程,但我仍然在玩:

class A {
private:
    class B {};

public:
    B getB() {
        return B();
    };
};

从 C++03 开始​​,这个类编译得很好,但是没有漂亮的方法getB() 的结果分配给一个左值,从某种意义上说:

A::B b = A().getB();

不编译。

我通过使用中间模板得到它,以这种方式:

template <typename T>
struct HideType {
    typedef T type;
};

HideType<A::B>::type b = A().getB();

但这看起来很糟糕,对于获取 A::B 左值变量的简单任务。

从 C++11 开始,这不再是真的,或者至少在 gcc 中不是这样。此代码仍然无效:

A::B b = A().getB();

但这有效的:

auto b = A().getB();

这方面的标准有漏洞吗?

【问题讨论】:

标签: c++ c++11 language-lawyer


【解决方案1】:

来自标准,第 11 条(成员访问控制):

类的成员可以是
- 私人的;也就是说,它的 name 只能由声明它的类的成员和朋友使用。
——受保护;也就是说,它的name只能由它所在班级的成员和朋友使用 由从该类派生的类和它们的朋友声明(参见 11.4)。
- 上市;也就是说,它的名称可以在任何地方使用而不受访问限制。

因此访问控制应用于名称

auto b = A().getB();

您不使用私人名称,因此根据标准,这是合法的

【讨论】:

    【解决方案2】:

    A::B b = A().getB() 不起作用的事实是因为BA 的私​​有类成员。如果您将其公开,那么您的代码将被编译。它适用于auto,因为auto 只检查分配给它的对象的类型,而无需调用对象的构造函数(就像declval)。所以它分配b,返回类型为getB,存在于类A中。您也可以通过以下方式更改您的代码:

    decltype( declval<A>().getB() ) b = A().getB();
    

    ( 如果declval 对你来说是新的,那么我必须告诉你它会返回一个类(这里是@987654334)的函数返回类型的右值(这里是getB,其返回类型是B) @) 而不调用类的构造函数!(但这应该只与decltypesizeof 之类的函数一起使用。)因此它可以避免创建类对象然后使用它的函数的开销。)

    现在根据我的说法,我不认为这是标准中的漏洞,而是我觉得漏洞已经被删除了!从您自己的代码中可以明显看出,请参阅函数getB。实例化 B 的对象是多么困难,因为它是在 private 中定义的!在这种情况下,使用B 变得很困难。这背后的想法是,A 类中的类型名称(即B)是不可访问的,但该类型仍然可用,这就是为什么您可以获得B 的对象。看懂这个模板代码就可以理解auto的用法了:-

    #include <iostream>
    #include <type_traits>  // for std::is_same
    using namespace std;
    class A
    {
        class B
        {};
        public:
        B getB()
        {
            return B();
        }
    };
    template<typename T>
    void check (T b)
    {
        cout<<boolalpha;
        is_same<decltype( declval<A>().getB() ), T> x;  // checks if T & B are of same type
        cout<<x.value<<'\n';
    }
    int main()
    {
        A obj;
        check (obj.getB());
        return 0;
    }
    

    输出:-

    true
    

    由于template 可以识别B,因此auto 也可以识别B

    【讨论】:

    • "它适用于auto,因为auto 就是这样!!!!它只会检查分配给它的类型是否有效" 这是都是胡言乱语。
    • 而且decltype是C++11,和auto一样,那么推荐它有什么意义呢?
    • 这只是一个额外的信息,告诉 OP 您可以访问B 的对象,甚至无需使用auto
    【解决方案3】:

    标准草案中似乎存在这样的缺陷,但已被WP 1170 更正。

    可能存在编译器错误。声明auto b = A().getB(); 涉及auto type-specifier 的模板参数推导,因此根据 C++11 标准它应该是格式错误的,因为该类型推导失败。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 2015-03-06
      • 2017-02-10
      • 2020-08-23
      相关资源
      最近更新 更多