36

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?

Leo91
  • 1,741
  • 3
  • 13
  • 20
  • 3
    A primary example would be e.g. a linked list. Why expose the node structure to the world, instead it can be a private structure inside the list class. In other words, it's the same as member variables, information hiding, abstraction, and general encapsulation.. – Some programmer dude Jul 09 '15 at 07:13
  • So it's only an encapsulation goodness? But why their choosed to make private members invisible to inner class? – Leo91 Jul 09 '15 at 07:16
  • 1
    _"I discover that private attributes of "container" class are not visibile by inner class"_ Unless you are a time traveller from 2001 you are mistaken, or you need to upgrade your compiler to something from this decade. – Jonathan Wakely Jul 09 '15 at 09:04
  • @JonathanWakely I'm new to C++ so I'm not a time traveler neither a person that knows wich compiler use. :) – Leo91 Jul 09 '15 at 10:17
  • I suggest you use a recent compiler, not an ancient one. You'll have a better experience. – Jonathan Wakely Jul 09 '15 at 10:28
  • 1
    possible duplicate of [Why would one use nested classes in C++?](http://stackoverflow.com/questions/4571355/why-would-one-use-nested-classes-in-c) – Hong Ooi Jul 09 '15 at 15:57
  • @HongOoi did not see it after search... :( – Leo91 Jul 09 '15 at 17:41
  • Which compiler *are* you using? And which mode are you using it in? If you're not on Windows, I'd suggest `clang++` using `-std=c++14`. – Kyle Strand Nov 07 '15 at 22:38

3 Answers3

49

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

Community
  • 1
  • 1
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • 1
    +1, but you don't need header trickery. Nothing stops you maing the nested class a `friend` of the containing class. – Angew is no longer proud of SO Jul 09 '15 at 07:38
  • 2
    Before c++11 you could use friend, no? – MikeMB Jul 09 '15 at 07:39
  • 1
    _"This rule changed in C++ 11"_ No, the rule changed for C++03, not C++11, see [DR 45](http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45) which was voted into the working paper in 2001. – Jonathan Wakely Jul 09 '15 at 09:02
  • 1
    @JonathanWakely if I'm not wrong final (14882) version of C++03 TC still said _"The members of a nested class have no special access..."_ and GCC did adhere to that rule when compiling with -std=c++03 (I don't remember about MSVC, I think it didn't). DR45 _outlined_ the problem (officially fixed later in C++11) – Adriano Repetti Jul 09 '15 at 09:18
  • 2
    @AdrianoRepetti, you're right, the wording didn't actually change in C++03, but GCC still implemented this **years** ago in C++98 mode (before it even had a `-std=c++03` option and before DR45 was resolved, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=359 reported in 2000). I think 2.95 was the last release to support the C++98 rule and that is prehistoric. – Jonathan Wakely Jul 09 '15 at 09:24
  • esti qu'cest dla marde – douche_satan Mar 03 '21 at 21:38
6

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

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.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165