不应该禁止访问私有类型吗?
Shouldn't access to private types be prohibited?
考虑这段代码:
class A
{
struct B {};
std::vector<B> _vec;
public:
const std::vector<B>& get() const { return _vec; }
};
请注意 B
在 class A
中是私有的。上面的代码可以编译,但是当从外部 class A
调用 get()
时,它不会:
const std::vector<A::B>& vec = get(); // does not compile
的确,A::B
是 private
。但是,从 C++11
开始,您可以简单地这样做:
const auto& vec = get();
效果很好。
出于与上述相同的原因,您不能执行以下操作:
A::B obj;
但是,因为有一个 public
getter,你可以从那个 getter 函数中推断出类型。在这种特殊情况下,可以这样做:
using B = std::decay<decltype(C{}.get())>::type::value_type;
B obj;
问题
我不确定如何表述我的问题。我觉得很奇怪,从 C++11 开始(而不是之前),我们实际上可以将 A::B
实例化为后者 private
。更重要的是,我认为我们可以调用 const auto& get()
很奇怪。对此有什么解释吗?不允许这样做不是更好吗?我应该声明 A::B
public
吗?我觉得如果你需要像上面代码中那样的 getter 函数,声明它 private
是没有意义的。
当您将某些内容标记为私有时,并不意味着无法访问。它只是意味着声明不能从外部访问。
例如,这将起作用:
class A {
struct B {};
public:
using C = B;
};
auto main() -> int {
auto c = A::C{};
}
我在这里访问 B
,因为我使用了 public 别名。
私人会员也一样:
class A {
int i;
public:
auto the_i() -> int A::* {
return &A::i;
}
};
auto main() -> int {
auto a = A{};
auto member = a.the_i();
// Whoa! I access the member directly! Shouldn't this prohibited?
a.*member = 9;
}
答案是否定的。声明是私有的,但仍然可以通过其他方式访问。
成员类型也是一样,暴露在public接口中,用户就可以使用了。
如果你不想让用户使用私有类型,就不要在public接口中暴露它。
It seems strange to me that, from C++11 on (and not before), we actually can instantiate A::B being the latter private.
您可以通过模板参数推导在 C++98/03 中很好地完成它:
template<typename T>
void temp_func(const T &t)
{
...
T u = t;
}
temp_func(a.get()); //Will use the private type.
您甚至可以在 temp_func
中使用 T
。
将类型设为私有 永远不会 保证无法从外部访问该类型。 Private 始终指的是 name 的可访问性,而不是名称背后的结构的可访问性。如果您希望一个类型只在一个范围内使用,那么该类型名称不能是任何非私有接口的一部分。而且一直都是这样。
Should I declare A::B
public?
这取决于你。但是,如果您公开一个 public 用户界面,那么您就是在声明用户可以 使用该界面 。为了让用户知道如何使用 vector<A::B>
,他们必须知道 A::B
的行为方式。所以他们必须使用它的定义。尽管它是私人的。
因此,如果用户必须了解一种类型以及一种类型的行为方式...真的是 "private" 吗?
考虑这段代码:
class A
{
struct B {};
std::vector<B> _vec;
public:
const std::vector<B>& get() const { return _vec; }
};
请注意 B
在 class A
中是私有的。上面的代码可以编译,但是当从外部 class A
调用 get()
时,它不会:
const std::vector<A::B>& vec = get(); // does not compile
的确,A::B
是 private
。但是,从 C++11
开始,您可以简单地这样做:
const auto& vec = get();
效果很好。
出于与上述相同的原因,您不能执行以下操作:
A::B obj;
但是,因为有一个 public
getter,你可以从那个 getter 函数中推断出类型。在这种特殊情况下,可以这样做:
using B = std::decay<decltype(C{}.get())>::type::value_type;
B obj;
问题
我不确定如何表述我的问题。我觉得很奇怪,从 C++11 开始(而不是之前),我们实际上可以将 A::B
实例化为后者 private
。更重要的是,我认为我们可以调用 const auto& get()
很奇怪。对此有什么解释吗?不允许这样做不是更好吗?我应该声明 A::B
public
吗?我觉得如果你需要像上面代码中那样的 getter 函数,声明它 private
是没有意义的。
当您将某些内容标记为私有时,并不意味着无法访问。它只是意味着声明不能从外部访问。
例如,这将起作用:
class A {
struct B {};
public:
using C = B;
};
auto main() -> int {
auto c = A::C{};
}
我在这里访问 B
,因为我使用了 public 别名。
私人会员也一样:
class A {
int i;
public:
auto the_i() -> int A::* {
return &A::i;
}
};
auto main() -> int {
auto a = A{};
auto member = a.the_i();
// Whoa! I access the member directly! Shouldn't this prohibited?
a.*member = 9;
}
答案是否定的。声明是私有的,但仍然可以通过其他方式访问。
成员类型也是一样,暴露在public接口中,用户就可以使用了。
如果你不想让用户使用私有类型,就不要在public接口中暴露它。
It seems strange to me that, from C++11 on (and not before), we actually can instantiate A::B being the latter private.
您可以通过模板参数推导在 C++98/03 中很好地完成它:
template<typename T>
void temp_func(const T &t)
{
...
T u = t;
}
temp_func(a.get()); //Will use the private type.
您甚至可以在 temp_func
中使用 T
。
将类型设为私有 永远不会 保证无法从外部访问该类型。 Private 始终指的是 name 的可访问性,而不是名称背后的结构的可访问性。如果您希望一个类型只在一个范围内使用,那么该类型名称不能是任何非私有接口的一部分。而且一直都是这样。
Should I declare
A::B
public?
这取决于你。但是,如果您公开一个 public 用户界面,那么您就是在声明用户可以 使用该界面 。为了让用户知道如何使用 vector<A::B>
,他们必须知道 A::B
的行为方式。所以他们必须使用它的定义。尽管它是私人的。
因此,如果用户必须了解一种类型以及一种类型的行为方式...真的是 "private" 吗?