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

Leo*_*o91 32 c++ inner-classes

我正在研究一些C++,现在我正在与Java对抗它的相似之处.我知道Java中内部类的目的,但现在我正在尝试在C++中使用嵌套类,并且我发现"容器"类的私有属性不是嵌套类可见的,所以为什么我应该使用它们呢?另外,有没有办法使这些属性可见?

Adr*_*tti 46

我正在研究一些C++,现在我正在与Java对抗它的相似之处.

首先要知道C++嵌套类 Java中的静态嵌套类相似.C++语法中没有任何东西可以重现Java 嵌套类.

我发现内部类不能看到"容器"类的私有属性......

C++ 98

在C++中,内部类与普通类没有区别,它们不是类成员,因此它们不能访问容器类的私有成员(与Java或C#等其他语言不同).

C++ 03

嵌套类是类成员,但对它们可以访问的内容的限制仍然适用(另请参阅本答案末尾的奇怪事项部分).它被认为是标准缺陷(参见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 */ };
};
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之前你不能(当然除非你将它们声明为friends但是参见下一段),如果你需要这个功能,只需使用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中,嵌套类是类成员(但标准明确表示他们无法访问容器私有,也不能成为容器类的朋友).似乎没有希望,幸运的是大多数编译器允许我们这样做(不管标准是什么).

  • 在c ++ 11之前你可以使用朋友,不是吗? (2认同)
  • @AdrianoRepetti,你是对的,C++ 03中的措辞实际上并没有改变,但GCC仍然在C++ 98模式下实现了这个**年前(在它甚至有一个`-std = c +之前) + 03`选项,在DR45解决之前,请参阅2000年报告的https://gcc.gnu.org/bugzilla/show_bug.cgi?id=359).我认为2.95是支持C++ 98规则的最后一个版本,这是史前的. (2认同)

Bat*_*eba 6

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

功能对象通常以这种方式编码.