C++ - 嵌套 类 有什么意义?

C++ - What's the point of nested classes?

我正在学习一些 C++,现在我正在反对它与 Java 的相似之处。我知道 Java 中内部 classes 的用途,但现在我试图在 C++ 中使用嵌套 classes, 我发现 的私有属性=15=] class 对嵌套的 class 不可见,那我为什么要使用它们呢?另外,有没有办法让这些属性可见?

它提供了另一种很好的封装技术。将一个 class 完全放在另一个 class 的 命名空间 中会降低它对代码库其他部分的可见性。这有助于实现可扩展性并减轻您的维护负担。

函数对象通常以这种方式编码。

I'm studying a little of C++ and now I'm fighting against it's similitudes with Java.

首先请注意,C++ 嵌套 class 与 Java 中的 static 嵌套 相似 127=]es。 C++ 语法中没有任何内容可以重现 Java 嵌套 classes.

I discover that private attributes of "container" class are not visible by inner class...

C++ 98

在 C++ 内部 classes 与 normal classes 没有区别,它们不是 class members 那么他们就不能访问容器 class' 的私有成员(不像其他语言,如 Java 或 C#)。

C++ 03

嵌套 classes 是 class 成员,但对他们可以访问的内容的限制仍然适用(另请参阅本答案末尾的 奇怪的事情 部分).它被认为是一个标准缺陷(参见 DR45),然后一些编译器更早地实现了 C++0x 访问规则,甚至在为 C++03 编译时(特别是 GCC,感谢 Jonathan Wakely 发现了这一点)。

C++ 11

此规则在 C++ 11 中更改,现在嵌套的 classes 可以访问容器 class 的私有成员。从 §11.7:

A nested class is a member and as such has the same access rights as any other member.

当然你仍然需要一个实例来访问非静态成员。


...so why I should use them?

然后它们是 实现 组相关 class 的细节,并且它们有相同的 问题 关于它们的用法您可能有其他语言版本(新手清楚,初级)。他们最大的好处 IMO 是封装,例如你有这个:

class stream {
    virtual void write(const std::string text) = 0;
};

class channel {
public:
    virtual stream* get_stream() = 0;

    // Other methods...
};

class tcp_channel : public channel {
public:
    virtual stream* get_stream() {
        return new tcp_stream(this);
    }

private:
    class tcp_stream : public stream { /* implementation */ };
};

它们在某些情况下也有助于替换 嵌套命名空间:

class protocol {
public:
    virtual void create_connection() = 0;

    class tcp : public protocol { /* implementation */ };
    class shared_memory : public protocol { /* implementation */ };
    class named_pipes: public protocol { /* implementation */ };
};

auto media = protocol::tcp();

或隐藏实现细节:

class file_system_entry {
public:
    class file : public file_system_entry { };
    class directory : public file_system_entry { };

    std::time_t get_last_modified() { ... }

    void remove() { ... }
    virtual void copy_to(std::string path) = 0;

private:
    class local_handle {
        // Implementation details
    } _handle;
};

还有许多其他使用模式(另请参阅 Why would one use nested classes in C++? for a much better discussion), just remember not everyone will correctly understand (and use!) them. See also Pros and cons of using nested C++ classes and enumerations?

Also, is there a way to make visible those attributes?

在 C++ 11 之前你不能(当然除非你将它们声明为 friends 但请参阅下一段),如果你需要此功能只需使用 C++ 11 编译器(支持此功能)。 GCC 确实(很久以前)而且 MSVC 也有,我不知道其他编译器。

嵌套好友

C++ 11 访问规则和朋友 classes 之间有什么区别吗? 一般来说,它们 几乎等同 自动 访问更简单):

class container {
public:
    class nested;
    friend class nested;

    class nested { };
};

相比于:

class container {
public:
    class nested { };
};

但是,对于前向声明,您会有一些副作用。还请记住,从可访问性的角度来看,它们是等价的(访问,如友谊,不能继承也不能传递)。这些示例无法编译:

class external : public container::nested {
public:
    // No: only class declared inside "container"
    // has access to private members, we do not inherit that 
    void foo(container obj) { /* access a private member of obj*/ }
};

// No, "container" has not access to "nested" private members,
// visibility isn't reciprocal
void container::foo(container::nested obj) {
    // Access some private member of obj
}

// No, we don't have anything to do with container,
// visibility isn't transitive
void friendOfNested(container obj) {
    // Access some private member of obj
}

那么完全等价吗? ,因为 container 的朋友的私有成员在 nested 中是可访问的,如果它是 C++ 11 中的嵌套 class,但如果不是nestedcontainer 的朋友。鉴于此概述结构:

class container;

class another {
    friend class container;     
};

class container {
public:
    class nested { };   
};

nested 可以访问 another 的私有成员:

void container::nested::foo(another obj) {
    obj.somePrivateMember = 0;
}

之所以有效,是因为 nested 成员 container,因此友谊的传递限制不适用。在 C++ 11 之前,将 nested 声明为 container 的友元,该代码将无法编译,因为友谊不可传递。

怪事

我们假设我们总是可以将嵌套的 class 声明为其容器的友元?其实标准(SO/IEC14822:2003(E),11.8):

A friend of a class is a function or class that is not a member of the class...

那么我们不应该能够将nested声明为container的友元:在C++ 03中嵌套的class是class 成员(但标准明确表示他们无权访问容器私有对象,也不能成为容器 class 的好友)。似乎没有希望,幸运的是大多数编译器允许我们这样做(不管标准怎么说)。

不同就是不一样

Java 的 inner classes 创建假定与 outer[= 的对象相关联的对象17=] class,因此可以在不显式创建指针或引用的情况下从内部 class 的方法访问外部 class 的成员。 C++ 不这样做; nested class 只是一个 class,其定义嵌套在另一个 class 的定义中。这对于封装很方便,但仅此而已:它并不是要神奇地让该类型的对象知道包含类型的对象。