我正在学习一些C++,现在正在对抗它与Java的相似之处。我知道Java中内部类的用途,但现在我正在尝试在C++中使用嵌套类,我发现“容器”类的私有属性并不可被嵌套类看到,那么我为什么要使用它们呢?此外,有没有一种方法可以使这些属性可见?
我正在学习一些C++,现在正在对抗它与Java的相似之处。我知道Java中内部类的用途,但现在我正在尝试在C++中使用嵌套类,我发现“容器”类的私有属性并不可被嵌套类看到,那么我为什么要使用它们呢?此外,有没有一种方法可以使这些属性可见?
在C++11中,这个规则已经改变了,现在嵌套类可以访问容器类的私有成员。来自§11.7:
嵌套类是一个成员,因此具有与任何其他成员相同的访问权限。
当然,您仍然需要一个实例才能访问非静态成员。
...那么我为什么应该使用它们?
它们是用来分组相关类的一个实现细节,在使用上可能会有一些与其他语言相同的问题(对于新手来说不够清晰,主要性)。在我看来,它们最大的好处是封装,例如你有这样一个场景:
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 */ };
};
在某些情况下,它们也有助于替代嵌套的命名空间:substitute。
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;
};
有许多其他的使用模式(另请参见为什么要在C ++中使用嵌套类? 进行更好的讨论),只需记住并非每个人都会正确地理解(和使用!)它们。另请参见使用嵌套C ++类和枚举的优缺点?
此外,是否有一种方法可以使这些属性可见?
C++ 11之前你不能(除非你将它们声明为friend
,但请参见下一段),如果您需要此功能,请使用支持此功能的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
}
它们是完全等价的吗?不是,因为在C++ 11中,如果nested
是一个嵌套类,则container
的友元的私有成员在nested
中是可访问的,但如果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
的友元,则该代码不会编译,因为友元关系不具有传递性。nested
作为container
的友元:在C++03中,嵌套类是类成员(但标准明确表示它们无法访问容器私有成员,也无法成为容器类的友元)。看来没有希望,幸运的是大多数编译器允许我们这样做(不管标准说了什么)。-std=c++03
选项之前和 DR45 得到解决之前,参见 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=359,该问题报告于2000年)。我认为2.95是最后一个支持 C++98 规则的版本,那已经是史前时期了。 - Jonathan Wakely它提供了另一种很好的封装技术。将一个类完全放在另一个类的命名空间中,可以降低它在代码库中的可见性。这有助于实现可扩展性并减少维护负担。
函数对象通常以这种方式编码。