Why Would One Use Nested Classes

Why should I use nested classes?

There are several reasons for using nested classes, among them:

  1. It is a way of logically grouping classes that are only used in one place.

  2. It increases encapsulation.

  3. Nested classes can lead to more readable and maintainable code.

  4. Child to parent class connection is simpler as it visually illustrates the variables and methods of each class.

When is really useful to use a nested Java class?

The most concise summary of when to use a nested class is: when that class is logically part of the outer class' API, or when it encapsulates behavior specific to the outer class.

For example, Map.Entry: it's an entry in a mapping. It's logically part of Map's API, so it makes sense to put it inside Map.

Another common example is Builder classes: you use a Builder to make a thing, so it makes sense to put it inside that thing.

These are classes that you only really use in the context of using the outer classes: sometimes you might use a Map.Entry by itself as some sort of pair class; and sometimes you might want to use a Builder by itself, for example as a parameter to a method which puts things into that builder, but doesn't actually do the building itself. These cases are probably rarely far from code that also uses the outer class too: you're still using some aspect the outer class' API, so they do still logically belong to that API.

You could put such classes at the top level, alongside the "main" class. There are a few reasons why you might not want to do this:

  • It clutters the namespace. If you've got classes Foo, Bar, Baz etc, having FooBuilder, BarBuilder, BazBuilder at the top level just makes it harder to see the "useful" top level classes.

    • Google's protocol buffers generate a Builder class for every message type. Given the number of protocol buffers used in Google code, this clutter would be far too cumbersome.
  • Nested classes have access to private fields of the outer class, which may help you do certain things without unnecessarily exposing those fields.
  • You can refer to nested classes by qualifying the outer name, e.g. Outer.Builder, rather than having to explicitly import some.pkg.OuterBuilder as well as import some.pkg.Outer. Admittedly, I don't really care about the number of imports, since I just keep them collapsed in intellij.

You can also use them to encapsulate internal logic or intermediate state in the class: for example, I like to define private nested classes when I find myself passing around the same N parameters between private methods in a class. This is stuff that you don't want people outside your class to care about; it's merely convenient inside the class.

Why would one use nested classes in C++?

Nested classes are cool for hiding implementation details.

List:

class List
{
public:
List(): head(nullptr), tail(nullptr) {}
private:
class Node
{
public:
int data;
Node* next;
Node* prev;
};
private:
Node* head;
Node* tail;
};

Here I don't want to expose Node as other people may decide to use the class and that would hinder me from updating my class as anything exposed is part of the public API and must be maintained forever. By making the class private, I not only hide the implementation I am also saying this is mine and I may change it at any time so you can not use it.

Look at std::list or std::map they all contain hidden classes (or do they?). The point is they may or may not, but because the implementation is private and hidden the builders of the STL were able to update the code without affecting how you used the code, or leaving a lot of old baggage laying around the STL because they need to maintain backwards compatibility with some fool who decided they wanted to use the Node class that was hidden inside list.

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

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

What is the purpose of an inner class

You should inner classes if you need something specific to the class your working with. A good example of an inner class can be found here: java.awt.geom.Ellipse2D and the corresponding Ellipse2D.Double and Ellipse2D.Float (Ellipse2D source code). You could place those classes in a package, but they make a lot more sense as nested classes. They directly correspond to Ellipse2D and will have no use elsewhere; also, the fact that they are nested improves readability in code that uses them. On another note, if an inner class is very likely to be useful when more general, it is often better to generalize it and make a regular class.

Also, inner classes can directly access variables in the outer class. That means that an inner class can be used to change the outer class. It is still possible to get an instance of it to be used outside of either class. To illustrate what I am saying:

public class Example {
public static void main(String[] args) {
Foo foo = new Foo();
Foo.Bar bar = foo.getBar(); //note, cannot call new Foo.Bar(); as Bar is dependent on Foo
for (int i = 0; i < 50; i++){
System.out.println(bar.get());
}
}
}
class Foo {
int val;
Bar b;

public Foo(){
b = new Bar();
}
public Bar getBar(){
return b;
}
public class Bar{
public Bar(){
val++;
}
public int get(){
return val++;
}
}
}

Another possible use of inner classes is to create something like a wrapper class for an the truly wanted inner class, especially useful for a recursive class. This is used for implementing a LinkedList. At one time, I implemented such a list, not realizing that anything of the sort had been made before. The idea is that you have your LinkedList class, and a Node class within it (where each node only points to the next/previous node and holds a single value). Doing it this way simplifies the code. However, it doesn't make any sense for the Node class to be external to LinkedList, because what type of "node" would it be? Thus it should be an internal class.

What are reasons why one would want to use nested classes?

You've answered your own question. Use nested classes when you need a helper class that is meaningless outside the class; particularly when the nested class can make use of private implementation details of the outer class.

Your argument that nested classes are useless is also an argument that private methods are useless: a private method might be useful outside of the class, and therefore you'd have to make it internal. An internal method might be useful outside of the assembly, and therefore you'd make it public. Therefore all methods should be public. If you think that's a bad argument, then what is different about you making the same argument for classes instead of methods?

I make nested classes all the time because I am frequently in the position of needed to encapsulate functionality in a helper that makes no sense outside of the class, and can use private implementation details of the outer class. For example, I write compilers. I recently wrote a class SemanticAnalyzer that does semantic analysis of parse trees. One of its nested classes is LocalScopeBuilder. Under what circumstances would I need to build a local scope when I am not analyzing the semantics of a parse tree? Never. That class is entirely an implementation detail of the semantic analyzer. I plan to add more nested classes with names like NullableArithmeticAnalyzer and OverloadResolutionAnalyzer that are also not useful outside of the class, but I want to encapsulate rules of the language in those specific classes.

People also use nested classes to build things like iterators, or comparators - things that make no sense outside of the class and are exposed via a well-known interface.

A pattern I use quite frequently is to have private nested classes that extend their outer class:

abstract public class BankAccount
{
private BankAccount() { }
// Now no one else can extend BankAccount because a derived class
// must be able to call a constructor, but all the constructors are
// private!
private sealed class ChequingAccount : BankAccount { ... }
public static BankAccount MakeChequingAccount() { return new ChequingAccount(); }
private sealed class SavingsAccount : BankAccount { ... }

and so on. Nested classes work very well with the factory pattern. Here BankAccount is a factory for various types of bank account, all of which can use the private implementation details of BankAccount. But no third party can make their own type EvilBankAccount that extends BankAccount.



Related Topics



Leave a reply



Submit