Leo*_*o91 32 c++ inner-classes
我正在研究一些C++,现在我正在与Java对抗它的相似之处.我知道Java中内部类的目的,但现在我正在尝试在C++中使用嵌套类,并且我发现"容器"类的私有属性不是嵌套类可见的,所以为什么我应该使用它们呢?另外,有没有办法使这些属性可见?
Adr*_*tti 46
我正在研究一些C++,现在我正在与Java对抗它的相似之处.
首先要知道C++嵌套类与 Java中的静态嵌套类相似.C++语法中没有任何东西可以重现Java 嵌套类.
我发现内部类不能看到"容器"类的私有属性......
在C++中,内部类与普通类没有区别,它们不是类成员,因此它们不能访问容器类的私有成员(与Java或C#等其他语言不同).
嵌套类是类成员,但对它们可以访问的内容的限制仍然适用(另请参阅本答案末尾的奇怪事项部分).它被认为是标准缺陷(参见DR45),然后一些编译器早先实现了C++ 0x访问规则,即使在编译C++ 03时也是如此(特别是GCC,感谢Jonathan Wakely发现这一点).
此规则在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 */ };
};
Run Code Online (Sandbox Code Playgroud)
在某些情况下,它们也有助于替换嵌套的命名空间:
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();
Run Code Online (Sandbox Code Playgroud)
或者隐藏实现细节:
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;
};
Run Code Online (Sandbox Code Playgroud)
还有许多其他的使用模式(另请参阅为什么在C++中使用嵌套类?为了更好的讨论),请记住并非每个人都能正确理解(并使用!)它们.另请参阅使用嵌套C++类和枚举的优缺点?
另外,有没有办法让这些属性可见?
在C++ 11之前你不能(当然除非你将它们声明为friend
s但是参见下一段),如果你需要这个功能,只需使用C++ 11编译器(支持这个功能).GCC(很久以前)和MSVC一样,我不知道其他编译器.
C++ 11访问规则和朋友类之间有什么区别吗?一般来说,它们几乎相同(自动访问只是更简洁):
class container {
public:
class nested;
friend class nested;
class nested { };
};
Run Code Online (Sandbox Code Playgroud)
相比:
class container {
public:
class nested { };
};
Run Code Online (Sandbox Code Playgroud)
但是有了前瞻性声明,你会有一些副作用.还要记住,从可访问性的角度来看,它们是等价的(访问,如友谊,不是继承的,也不是传递的).这些示例不编译:
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
}
Run Code Online (Sandbox Code Playgroud)
那么完全相同吗?不,因为如果它是C++ 11中的嵌套类,那么container
朋友的私人成员是可访问的,nested
但如果他们是nested
朋友的话,他们就不会container
.鉴于这个概述的结构:
class container;
class another {
friend class container;
};
class container {
public:
class nested { };
};
Run Code Online (Sandbox Code Playgroud)
nested
可以访问another
的私人会员:
void container::nested::foo(another obj) {
obj.somePrivateMember = 0;
}
Run Code Online (Sandbox Code Playgroud)
它起作用,因为nested
是友好的传递限制的成员 container
不适用.在C++ 11之前,声明nested
为该朋友container
,该代码将无法编译,因为友谊不是传递性的.
我们假设我们总是可以声明一个嵌套类作为其容器的朋友?实际上标准说(SO/IEC 14822:2003(E),11.8):
类的朋友是不是该类成员的函数或类...
然后我们不应该声明nested
为朋友container
:在C++ 03中,嵌套类是类成员(但标准明确表示他们无法访问容器私有,也不能成为容器类的朋友).似乎没有希望,幸运的是大多数编译器允许我们这样做(不管标准是什么).