访问私有嵌套类

Accessing private nested class

本文关键字:嵌套 访问      更新时间:2023-10-16

我制作了这个简单的类,它仍然在我的脑海中播放:

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

这方面的标准是否存在漏洞?

根据标准,第11条(成员访问控制):

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

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

在中

auto b = A().getB();

根据标准

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

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

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

(如果declval对您来说是新的,那么我必须告诉您,它将返回类(此处为A)的函数(此处为返回类型为BgetB)的返回类型的右值,而不调用该类的构造函数!(不过,这应该只与decltypesizeof等函数一起使用。)因此,它可以避免创建类对象然后使用其函数的开销。)

现在根据我的说法,我不认为这是标准中的漏洞,而是我觉得这个漏洞已经被消除了!从您自己的代码中可以明显看出,请参阅函数getB。实例化B的对象是多么困难,因为它是在私有环境中定义的!在这种情况下,与CCD_ 19一起工作变得困难。这背后的想法是,类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

标准草案中似乎存在这样的缺陷,但WP 1170已对其进行了纠正。

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