C++ - What's the point of nested classes?

前端 未结 3 1922
星月不相逢
星月不相逢 2021-02-01 15:04

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 i

相关标签:
3条回答
  • 2021-02-01 15:15

    It provides another good encapsulation technique. Placing one class entirely within the namespace of another class reduces its visibility to other parts of your code base. This helps achieve scalability and reduces your maintenance burden.

    Function objects are often coded in such a manner.

    0 讨论(0)
  • 2021-02-01 15:32

    I'm studying a little of C++ and now I'm fighting against it's similitudes with Java.

    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.

    I discover that private attributes of "container" class are not visible by inner class...

    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:

    A nested class is a member and as such has the same access rights as any other member.

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


    ...so why I should use them?

    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?

    Also, is there a way to make visible those attributes?

    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):

    A friend of a class is a function or class that is not a member of the class...

    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).

    0 讨论(0)
  • 2021-02-01 15:41

    Different isn't the same.

    Java's inner classes create objects that are assumed to be connected with an object of the outer class, so access to members of the outer class from methods of the inner class can be done without explicitly creating a pointer or reference. C++ doesn't do that; a nested class is just a class whose definition is nested inside the definition of another class. That's handy for encapsulation, but that's it: it's not intended to magically make objects of that type know about objects of the containing type.

    0 讨论(0)
提交回复
热议问题