我正在学习一点 C++,现在我正在与它与 Java 的相似性作斗争。
首先请注意,C++ 嵌套类类似于与 Java 中的静态嵌套类。 C++ 语法中没有任何东西可以重现 Java 嵌套类。
我发现内部类看不到“容器”类的私有属性...
C++ 98
在 C++ 中,内部类与普通类没有什么不同,它们不是类成员,因此它们无法访问容器类的私有成员(与其他语言不同像 Java 或 C#)。
C++ 03
嵌套类是类成员,但对它们可以访问的内容的限制仍然适用(另请参阅此答案末尾的 Weird things 部分)。它被认为是一个标准缺陷(参见 DR45),然后一些编译器更早地实现了 C++0x 访问规则,即使在为 C++03 编译时也是如此(尤其是 GCC,感谢 Jonathan Wakely 发现了这一点)。
C++ 11
这个规则在 C++ 11 中改变了,现在嵌套类可以访问容器类的私有成员。从§11.7:
嵌套类是一个成员,因此具有与任何其他成员相同的访问权限。
当然你仍然需要一个实例来访问非静态成员。
...那我为什么要使用它们?
它们是一个实现详细信息,用于对相关类进行分组,并且它们在使用其他语言时可能存在相同的问题(新手清晰,主要) .他们最大的好处是 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++? 以获得更好的讨论),请记住并非每个人都会正确理解(并使用!)它们。另见Pros and cons of using nested C++ classes and enumerations?
另外,有没有办法让这些属性可见?
在 C++ 11 之前,您不能(当然,除非您将它们声明为 friends,但请参阅下一段),如果您需要此功能,只需使用 C++ 11 编译器(支持此功能)。 GCC(很久以前)和 MSVC 一样,我不知道其他编译器。
嵌套好友
C++ 11 访问规则和友元类之间有什么区别吗?一般来说,它们几乎等价(自动访问只是更少详细):
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 中的嵌套类,但如果 nested 是 container 的朋友,则不能访问。鉴于此概述的结构:
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 的朋友,该代码将无法编译,因为友谊不具有传递性。
奇怪的事情
我们假设我们总是可以将嵌套类声明为其容器的朋友?其实标准说(SO/IEC 14822:2003(E), 11.8):
类的朋友是不是类成员的函数或类...
那么我们不应该能够将nested 声明为container 的朋友:在C++ 03 中,嵌套类是类成员(但标准明确表示它们无权访问容器私有和他们也不能成为容器类的朋友)。似乎没有希望了,幸运的是大多数编译器都允许我们这样做(不管标准如何规定)。