12

有时,C++ 的隐私概念让我感到困惑 :-)

class Foo
{
    struct Bar;
    Bar* p;

public:

    Bar* operator->() const
    {
        return p;
    }
};

struct Foo::Bar
{
    void baz()
    {
        std::cout << "inside baz\n";
    }
};

int main()
{
    Foo::Bar b;   // error: 'struct Foo::Bar' is private within this context

    Foo f;
    f->baz();     // fine
}

既然Foo::Bar是,private我不能申报b。但是我可以很好main地调用方法。Foo::Bar为什么这是允许的?这是意外还是设计使然?


哦,等等,它变得更好了:

Foo f;
auto x = f.operator->();   // :-)
x->baz();

即使我不允许命名类型Foo::Bar,它也适用于auto...


诺亚写道:

在类定义中定义的类型名称不能在没有限定的情况下在其类之外使用。

只是为了好玩,以下是从外部获取类型的方法:

#include <type_traits>

const Foo some_foo();

typedef typename std::remove_pointer<decltype( some_foo().operator->() )>::type Foo_Bar;
4

3 回答 3

6

试图在标准中找到可以详细说明的任何内容,但我做不到。我唯一能找到的是9.9:

类型名称遵循与其他名称完全相同的范围规则。特别是,在类定义中定义的类型名称不能在没有限定的情况下在其类之外使用。

本质上,Foo::Bar 的名称是 Foo 私有的,而不是定义。因此,您可以在 Foo 之外使用 Bars,只是不能按类型引用它们,因为该名称是私有的。

成员的名称查找规则似乎对此也有一些影响。我没有看到任何专门引用“嵌套类”的东西,因此它们不会被允许(如果我实际上没有找到任何东西是因为它不存在)。

于 2010-06-01T18:49:21.130 回答
3

我无法提供完整的答案,但可能是一个起点。C++ 1998 规范在第 11.3 段[class.access](第 175 页)下包含以下代码示例:

class A
{
    class B { };
public:
    typedef B BB;
};

void f()
{
    A::BB x;   // OK, typedef name A::BB is public
    A::B y;    // access error, A::B is private
}

在此示例中,私有类型通过 public 被“发布” typedef。虽然这与通过成员函数签名发布类型不是一回事,但它是相似的。

于 2010-06-01T18:53:10.620 回答
1

我认为这是设计使然。您不能显式创建实例,Foo::Bar但它可以从成员函数返回,然后您可以将其传递给其他成员函数。这使您可以隐藏类的实现细节。

于 2010-06-01T19:32:12.210 回答