C++ private nested class - 访问不同的函数
C++ private nested class - access to different functions
发现了这个奇怪的编译行为,检查了 VS2012、VS2017 和 https://www.onlinegdb.com/online_c++_compiler)
基本上,对于私有嵌套 类,您可以在外部调用 public 函数,但不能调用 public 构造函数。
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() {}
};
.....
};
然后调用它。
如果从实例调用静态不是纯粹的标准事物,则 createObject() 可能是非静态的。
c.innerVect.push_back(c.inner.createObject()); // COMPILING
到"hack"编译
成员是public当然可以调用它的成员函数。如果它的名字可见,那么它自己的 public 成员也是如此。
同样,内部 class 是私有的,因此您当然不能从 class 外部引用它的名称。这些是访问控制规则的基本定义。
emplace_back
可以调用构造函数,因为 std::vector
从允许引用它的人那里接收到类型作为模板参数。实例化模板时发生访问检查。那时它的名字是可以访问的。
您可以在 class 之外的任何地方使用 decltype
:
调用构造函数
Outer c;
auto this_works_too = decltype(c.inner){};
之所以有效,是因为您不必使用无法访问的名称来引用它。
成员"createObject()"是私有的。因此,您当然无法访问它。您应该在 public 字段中添加一些成员函数来实现此私有成员。
注意嵌套的struct
PrivateInner
声明为private
,所以只有Outer::PrivateInner
是private
,不能用这个名字来在没有足够访问权限的情况下像 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
这样的名称;它使用指定的名称作为模板参数。
顺便说一句:出于同样的原因,
c.innerVect.push_back(c.inner.createObject()); // COMPILING
但 c.innerVect.push_back(Outer::PrivateInner::createObject());
无法编译。
访问控制应用于名称。这意味着只有 struct
PrivateInner
的名称受到限制。 struct
本身的成员有自己的访问控制。所以 PrivateInner
的所有成员都是 public.
11 Member access control [class.access]
1 A member of a class can be
- private; that is, its name can be used only by members and friends of the class in which it is declared.
...
4 Access control is applied uniformly to all names, whether the names
are referred to from declarations or expressions. ...
正如您已经发现的那样,如果您不使用其名称,则可以使用构造函数(以及一般的 struct
):
c.innerVect.push_back({});
c.innerVect.emplace_back();
甚至
template <typename T>
T createPrivateInner()
{
return T();
}
...
c.innerVect.push_back(createPrivateInner<decltype(Outer::inner)>());
发现了这个奇怪的编译行为,检查了 VS2012、VS2017 和 https://www.onlinegdb.com/online_c++_compiler)
基本上,对于私有嵌套 类,您可以在外部调用 public 函数,但不能调用 public 构造函数。
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() {}
};
.....
};
然后调用它。
如果从实例调用静态不是纯粹的标准事物,则 createObject() 可能是非静态的。
c.innerVect.push_back(c.inner.createObject()); // COMPILING
到"hack"编译
成员是public当然可以调用它的成员函数。如果它的名字可见,那么它自己的 public 成员也是如此。
同样,内部 class 是私有的,因此您当然不能从 class 外部引用它的名称。这些是访问控制规则的基本定义。
emplace_back
可以调用构造函数,因为 std::vector
从允许引用它的人那里接收到类型作为模板参数。实例化模板时发生访问检查。那时它的名字是可以访问的。
您可以在 class 之外的任何地方使用 decltype
:
Outer c;
auto this_works_too = decltype(c.inner){};
之所以有效,是因为您不必使用无法访问的名称来引用它。
成员"createObject()"是私有的。因此,您当然无法访问它。您应该在 public 字段中添加一些成员函数来实现此私有成员。
注意嵌套的struct
PrivateInner
声明为private
,所以只有Outer::PrivateInner
是private
,不能用这个名字来在没有足够访问权限的情况下像 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
这样的名称;它使用指定的名称作为模板参数。
顺便说一句:出于同样的原因,
c.innerVect.push_back(c.inner.createObject()); // COMPILING
但 c.innerVect.push_back(Outer::PrivateInner::createObject());
无法编译。
访问控制应用于名称。这意味着只有 struct
PrivateInner
的名称受到限制。 struct
本身的成员有自己的访问控制。所以 PrivateInner
的所有成员都是 public.
11 Member access control [class.access]
1 A member of a class can be
- private; that is, its name can be used only by members and friends of the class in which it is declared.
...
4 Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions. ...
正如您已经发现的那样,如果您不使用其名称,则可以使用构造函数(以及一般的 struct
):
c.innerVect.push_back({});
c.innerVect.emplace_back();
甚至
template <typename T>
T createPrivateInner()
{
return T();
}
...
c.innerVect.push_back(createPrivateInner<decltype(Outer::inner)>());