访问私有嵌套类

时间:2015-12-13 13:36:41

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

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

class A {
private:
    class B {};

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

从C ++ 03开始,这个类编译得很好,但是没有漂亮的方式getB()的结果分配给左值,意思是:< / p>

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();

标准方面是否存在漏洞?

3 个答案:

答案 0 :(得分:9)

从标准,第11条(会员访问控制):

  

班级成员可以是   - 私人的;也就是说,它的名称只能由声明它的类的成员和朋友使用。
   - 受保护;也就是说,它的名称只能由其所在类的成员和朋友使用   通过该类派生的类及其朋友宣布(见11.4)   - 上市;也就是说,它的名称可以在没有访问限制的任何地方使用。

因此,访问控制适用于名称

auto b = A().getB();

根据标准

,您不使用私人名称,因此它是合法的

答案 1 :(得分:1)

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

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

(如果declval对您来说是新的,那么我必须告诉您它将返回函数返回类型的右值(此处为getB,其返回类型为B)一个类(这里A)没有调用类的构造函数!(但是这应该仅用于decltypesizeof之类的函数。)因此它可以防止创建类的开销对象然后使用它的功能。)

现在根据我的说法,我认为这不是标准中的漏洞而是我觉得漏洞已被删除!从您自己的代码中可以看出,请参阅函数getB。实例化B的对象有多困难,因为它是私有定义的!在这种情况下,使用B变得困难。这背后的想法是类B中的类型名称(即A)是不可访问的,但类型仍然可用,这就是为什么你可以获得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

答案 2 :(得分:0)

看来,标准草案中存在这样的缺陷,但已由WP 1170更正。

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