本文介绍了C ++ - 嵌套类的要点是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习一点C ++,现在我打击它与Java的相似性。我知道Java中内部类的目的,但现在我试图在C ++中使用嵌套类,,我发现容器类的私有属性不可见嵌套类,所以为什么我应该使用它们?

解决方案

首先要知道C ++嵌套类是类似与您在Java中调用静态嵌套类类似。 C ++语法中没有任何东西可以再现Java嵌套类。



C ++ 98



在C ++内部类与普通类不同,它们不是类成员,那么他们不能访问容器类的私有成员Java或C#)。



C ++ 03



嵌套类是类成员,但对它们可以访问的限制仍然适用奇怪的事情)。它已被视为标准缺陷(请参阅)那么一些编译器早期实现C ++ 0x访问规则,即使在编译C ++ 03(特别是GCC,感谢Jonathan Wakely发现这一点)。



C ++ 11



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

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






然后是一个实现细节,以便对相关类进行分组,并且他们对于其他语言(新手,主要的清晰度)的使用有相同的问题。他们最大的好处IMO是封装,如果你有例如:

 类流{
virtual void write std :: string text)= 0;
};

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

//其他方法...
};

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

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

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

 类协议{
public:
virtual void create_connection()= 0;

类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 {};
类目录:public file_system_entry {};

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

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

private:
class local_handle {
//实现细节
} _handle;
};

有很多其他的使用模式(另见更好的讨论),只是记住不是每个人都会正确地理解(和使用!另请参见


在C ++ 11之前,你可以' t(当然除非你将它们声明为 friend s但看下一段),如果你需要这个功能只需使用C ++ 11编译器(支持这个功能)。 GCC(从很久以前)和MSVC都做,我不知道其他编译器。



嵌套的朋友



C ++ 11访问规则和朋友类之间有什么区别吗? strong>一般来说,几乎等同于自动访问只是较少冗长):

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

class nested {};
};相比:

 

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

但是对于forward声明你有一些还记得从可访问性的角度来看,他们是等价的(访问,像友谊,不是继承也不是传递)。这些示例不编译:

  class external:public container :: nested {
public:
//否:只有在container中声明的类
//可以访问私有成员,我们不继承
void foo(container obj){/ *访问obj的私有成员* /}
};

//不,container无法访问嵌套的私有成员,
//可见性不是互惠的
void container :: foo(container :: nested obj){
//访问obj的一些私有成员
}

//不,我们没有任何关系到容器,
//可见性不是可传递的
void friendOfNested(container obj){
//访问obj的一些私有成员
}

那么完全等效吗? ,因为 container 的私人成员可在嵌套中访问C ++ 11中的嵌套类,但是如果嵌套 container 的朋友,则不是。给定这个概括的结构:

  

class another {
friend class container;
};

类容器{
public:
class nested {};
};

嵌套可以存取另一个的私人成员:

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

这是因为嵌套 容器成员,那么对友谊的传递限制不适用。在C ++ 11之前,声明嵌套 container 的朋友,该代码将无法编译,因为友谊不是传递性的。



奇怪的事情



我们假设我们总是可以声明一个嵌套类作为其容器的朋友?实际上标准表示(SO / IEC 14822:2003(E),11.8):

然后我们不应该嵌套 container 的朋友:嵌套类是类成员说他们没有访问容器私有,也不能是容器类的朋友)。似乎没有希望,幸运的是,大多数编译器允许我们这样做(不管什么标准说)。


I'm studying a little of C++ and now I'm fighting against it's similitudes with Java. I know the purpose of inner classes in Java, but now I'm trying to use nested classes in C++, and I discover that private attributes of "container" class are not visibile by nested class, so why I should use them? Also, is there a way to make visibile those attributes?

解决方案

First of all be aware that C++ nested classes are similar to what in Java you call static nested classes. There isn't anything in C++ syntax to reproduce Java nested classes.

C++ 98

In C++ inner classes aren't different to normal classes, they're not class members then they can't access container class' private members (unlike other languages like Java or C#).

C++ 03

Nested classes are class members but restrictions on what they can access still applies (see also section Weird things at the end of this answer). It has been considered a standard defect (see DR45) then some compilers earlier implemented C++0x access rule earlier even when compiling for C++03 (notably GCC, thanks to Jonathan Wakely to spot this out).

C++ 11

This rule changed in C++ 11, now nested classes can access private member of container class. From §11.7:

Of course you still need an instance to access non static members.


They're then an implementation detail to group related classes and they have same issues about their usage that you may have in other languages (clarity for newbies, primary). Their greatest benefit IMO is encapsulation, if for example you have this:

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 */ };
};

They're also helpful in some circumstances to substitute nested namespaces:

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();

Or to hide implementation details:

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;
};

There are many others usage patterns (see also 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?

Before C++ 11 you can't (of course unless you declare them as friends but see next paragraph), if you need this feature just use a C++ 11 compiler (that supports this feature). GCC does (from long time ago) and also MSVC does, I don't know about other compilers.

Nested Friends

Is there any difference between C++ 11 access rules and friend classes? In general they're almost equivalent (automatic access is just less verbose):

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

    class nested { };
};

Compared to:

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

However with forward declaration you have some side effects. Also remember that from accessibility point of view they're equivalent (access, like friendship, is not inherited nor transitive). These examples don't compile:

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
}

Are then completely equivalent? No, because private members of container's friends are accessible in nested if it's a nested class in C++ 11 but they're not if nested is a friend of container. Given this outlined structure:

class container;

class another {
    friend class container;
};

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

nested can access another's private members:

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

It works because nested is a member of container then transitive restriction of friendship doesn't apply. Before C++ 11, declaring nested as friend of container, that code won't compile because friendship isn't transitive.

Weird things

We'd assume we can always declare a nested class as friend of its container? Actually standard said (SO/IEC 14822:2003(E), 11.8):

Then we shouldn't be able to declare nested as friend of container: in C++ 03 nested classes are class members (but standard explicitly said they have no access to container privates and also they can't be friends of container class). It seems there was no hope, fortunately most compilers allowed us to do so (regardless to what standard said).

这篇关于C ++ - 嵌套类的要点是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 02:26