不应该禁止访问私有类型吗?

时间:2019-09-06 13:39:27

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

考虑以下代码:

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

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

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

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& get()很奇怪。有什么解释吗?不允许这样做不是更好吗?我应该声明A::B public吗?如果您需要像上面代码中的getter函数一样,我认为声明private没有任何意义。

2 个答案:

答案 0 :(得分:3)

  

对于我来说,奇怪的是,从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.

您甚至可以在T内使用temp_func

将类型设为私有永远不会 保证从外部无法访问该类型。私有始终指代名称的可访问性,而不是名称背后的构造。如果要只在范围内使用类型,则该类型名不能成为任何非私有接口的一部分。情况一直如此。

  

我应该宣布A::B公开吗?

由您决定。但是,如果公开了公共用户界面,则是在声明用户可以使用该界面。为了使用户知道如何使用vector<A::B>,他们必须知道A::B的行为。因此,他们必须使用其定义。即使是私人的。

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

答案 1 :(得分: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;
}

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

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

如果您不希望用户使用私有类型,只需不要在公共界面中公开它即可。