C ++私有嵌套类 - 访问不同的函数

时间:2018-02-02 15:25:38

标签: c++ class private

在VS2012,VS2017和https://www.onlinegdb.com/online_c++_compiler上检查了这种奇怪的编译行为

对于私有嵌套类,您可以在外部调用公共函数,但不能调用公共构造函数。

3个问题:

  • 编译器让我调用func()的原因是什么?

  • 如果编译器让我调用func(),为什么我不能调用ctor?

  • 如果我不能打电话给ctor,emplace_back怎么能这样做呢?

class Outer {
    struct PrivateInner {
        PrivateInner() {}
        void func() {}
    };
public:
    PrivateInner inner;
    std::vector<PrivateInner> innerVect;
};

void f1()
{
    Outer c;
    c.inner.func(); // COMPILING, but why?
}

void f2()
{
    Outer c;
    c.innerVect.push_back(Outer::PrivateInner()); // NOT COMPILING, why no access to ctor if there is access to func()?
    c.innerVect.emplace_back(); // COMPILING, but why? Doesn't it call Outer::PrivateInner inside?
}

正如我所见,我仍然可以创建一个(静态)函数createObject():

class Outer {
    struct PrivateInner {
        PrivateInner() {}
        static PrivateInner createObject() { return PrivateInner(); }
        void func() {}
    };
.....
};

然后调用它。

如果从实例调用static不是纯粹的标准事物,那么

createObject()可能是非静态的。

c.innerVect.push_back(c.inner.createObject()); // COMPILING

to&#34; hack&#34;汇编

4 个答案:

答案 0 :(得分:4)

请注意,嵌套的struct PrivateInner声明为private,因此只有Outer::PrivateInnerprivate,您无法使用此名称声明变量如Outer::PrivateInner pi;没有足够的访问权限,但您可以像decltype(Outer::inner) pi;一样编写它。

另一方面,它的构造函数和成员函数是public,因此可以调用它们。

c.inner.func(); // COMPILING, but why?

func()public,因此如果您有Outer::PrivateInner类型的实例,则可以在其上调用func

c.innerVect.push_back(Outer::PrivateInner()); // NOT COMPILING, why no access to ctor if there is access to func()?

它与构造函数无关,你不能在这里使用名称Outer::PrivateInner

c.innerVect.emplace_back(); // COMPILING, but why? Doesn't it call Outer::PrivateInner inside?

构造函数是public,然后它可以用来构造对象。 std::vector不直接使用Outer::PrivateInner之类的名称;它使用指定的名称作为模板参数。

BTW:出于同样的原因,

c.innerVect.push_back(c.inner.createObject()); // COMPILING

c.innerVect.push_back(Outer::PrivateInner::createObject());无法编译。

答案 1 :(得分:4)

访问控制适用于名称。这意味着只限制struct PrivateInner的名称。 struct本身的成员拥有自己的访问控制权。因此PrivateInner的所有成员都是公开的。

  

11会员访问控制[class.access]

     

1班级成员可以

     
      
  • 私有;也就是说,它的名称只能由声明它的类的成员和朋友使用。
  •   
     

...

     

4访问控制统一应用于所有名称,无论名称是什么   从声明或表达中引用。 ...

正如您已经发现的那样,如果您没有使用其名称,则可以使用构造函数(以及struct):

c.innerVect.push_back({});
c.innerVect.emplace_back();

甚至

template <typename T>
T createPrivateInner()
{
    return T();
}

...

c.innerVect.push_back(createPrivateInner<decltype(Outer::inner)>());

答案 2 :(得分:3)

该成员是公开的,因此您当然可以调用其成员函数。如果其名称可见,那么其公共成员也是如此。

同样,内部类是私有的,所以当然你不能从类外面引用它的名字。这些是访问控制规则的基本定义。

emplace_back可以调用构造函数,因为std::vector从允许引用它的人那里收到了类型作为模板参数。实例化模板时发生访问检查。那时它的名字是可以访问的。

您可以使用decltype在任何地方调用构造函数:

Outer c;
auto this_works_too = decltype(c.inner){};

这是有效的,因为您不必通过无法访问的名称来引用它。

答案 3 :(得分:0)

成员“createObject()”是私有的。所以,当然,你无法访问它。您应该在公共字段中添加一些成员函数来实现此私有成员。