【问题标题】:Shouldn't access to private types be prohibited?不应该禁止访问私有类型吗?
【发布时间】:2019-09-06 13:39:27
【问题描述】:

考虑这段代码:

class A
{
    struct B {};
    std::vector<B> _vec;

public:
    const std::vector<B>& get() const { return _vec; }
};

注意BA 类中是私有的。上面的代码可以编译,但是当从外部类A调用get()时,它没有:

const std::vector<A::B>& vec = get(); // does not compile

确实,A::Bprivate。但是,从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&amp; get() 很奇怪。对此有什么解释吗?不允许这样做不是更好吗?我应该声明A::B public 吗?如果您需要像上面代码中的 getter 函数,我觉得声明它 private 是没有意义的。

【问题讨论】:

  • 这就是语言的工作原理。 “我应该公开 A::B 吗?” 是的。
  • Q 前半部分非常相关/欺骗:stackoverflow.com/questions/13532784/…
  • name A::B 是私有的。这就是语言的工作方式。如果重要的是 A::B 满足一些 Concept 就可以了
  • @NathanOliver 感谢您指出这一点。可惜我一个人找不到那个帖子。似乎访问控制都是关于名称的。
  • @curiousguy 我的意思是一般意义上的,而不是这个特定的例子。 每一种语言都有可能让自己在脚下开枪; C++ 让它变得特别简单。

标签: c++ c++11 c++03


【解决方案1】:

我觉得奇怪的是,从 C++11 开始(而不是之前),我们实际上可以将 A::B 实例化为后者私有。

你可以在 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 的可访问性,而不是名称背后的构造。如果您希望类型仅在范围内使用,则该类型名不能是任何非私有接口的一部分。而且一直都是这样。

我应该将A::B公开吗?

这取决于你。但是,如果您公开一个公共用户界面,您就是在声明用户可以,您知道,使用该界面。为了让用户知道如何使用vector&lt;A::B&gt;,他们必须知道A::B 的行为方式。所以他们必须使用它的定义。即使它是私人的。

因此,如果用户必须了解一个类型以及一个类型的行为方式......它真的是“私有的”吗?

【讨论】:

  • 模板推演! +1。我也同意 A::B 并不是真正私有的。
【解决方案2】:

当您将某些内容标记为私有时,这并不意味着无法访问。它只是意味着不能从外部访问声明。

例如,这将起作用:

class A {
    struct B {};

public:
    using C = B;
};

auto main() -> int {
    auto c = A::C{}; 
}

我在这里访问B,因为我使用了它的公共别名。

私人会员也是如此:

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;
}

答案是否定的。声明是私有的,但仍然可以通过其他方式访问。

与成员类型相同,将其公开在公共界面中,用户将能够使用它。

如果您不希望用户使用私有类型,请不要在公共接口中公开它。

【讨论】:

  • 你访问成员 i 由于间接(你返回一个指针)。这在 C++11 之前也有效。问题是在 c++11 之前,我们无法访问具有私有声明类型的成员。
  • 这里的成员指针部分看不懂。有人认为这不起作用吗?
  • @geza 这是一个分析,只要您不使用该名称,就不会禁止访问。
猜你喜欢
  • 2016-04-07
  • 2016-06-30
  • 1970-01-01
  • 2011-01-05
  • 1970-01-01
  • 2019-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多