Why Would One Use Nested Classes in C++

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

Pros and cons of using nested C++ classes and enumerations?

Nested classes

There are several side effects to classes nested inside classes that I usually consider flaws (if not pure antipatterns).

Let's imagine the following code :

class A
{
public :
class B { /* etc. */ } ;

// etc.
} ;

Or even:

class A
{
public :
class B ;

// etc.
} ;

class A::B
{
public :

// etc.
} ;

So:

  • Privilegied Access: A::B has privilegied access to all members of A (methods, variables, symbols, etc.), which weakens encapsulation
  • A's scope is candidate for symbol lookup: code from inside B will see all symbols from A as possible candidates for a symbol lookup, which can confuse the code
  • forward-declaration: There is no way to forward-declare A::B without giving a full declaration of A
  • Extensibility: It is impossible to add another class A::C unless you are owner of A
  • Code verbosity: putting classes into classes only makes headers larger. You can still separate this into multiple declarations, but there's no way to use namespace-like aliases, imports or usings.

As a conclusion, unless exceptions (e.g. the nested class is an intimate part of the nesting class... And even then...), I see no point in nested classes in normal code, as the flaws outweights by magnitudes the perceived advantages.

Furthermore, it smells as a clumsy attempt to simulate namespacing without using C++ namespaces.

On the pro-side, you isolate this code, and if private, make it unusable but from the "outside" class...

Nested enums

Pros: Everything.

Con: Nothing.

The fact is enum items will pollute the global scope:

// collision
enum Value { empty = 7, undefined, defined } ;
enum Glass { empty = 42, half, full } ;

// empty is from Value or Glass?

Ony by putting each enum in a different namespace/class will enable you to avoid this collision:

namespace Value { enum type { empty = 7, undefined, defined } ; }
namespace Glass { enum type { empty = 42, half, full } ; }

// Value::type e = Value::empty ;
// Glass::type f = Glass::empty ;

Note that C++0x defined the class enum:

enum class Value { empty, undefined, defined } ;
enum class Glass { empty, half, full } ;

// Value e = Value::empty ;
// Glass f = Glass::empty ;

exactly for this kind of problems.

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.

Why/when should you use nested classes in .net? Or shouldn't you?

Use a nested class when the class you are nesting is only useful to the enclosing class. For instance, nested classes allow you to write something like (simplified):

public class SortedMap {
private class TreeNode {
TreeNode left;
TreeNode right;
}
}

You can make a complete definition of your class in one place, you don't have to jump through any PIMPL hoops to define how your class works, and the outside world doesn't need to see anything of your implementation.

If the TreeNode class was external, you would either have to make all the fields public or make a bunch of get/set methods to use it. The outside world would have another class polluting their intellisense.

Are C++ nested classes the right approach for encapsulation?

Constructing instances of nested classes

If you want the constructor of TRK to in turn cause the construction of a TRK::Fitting variable, the definition of TRK::Fitting must be completely known to it, a forward declaration is not enough. However, once you do that, you can intialize member variables of the nested class type just like you would always do. Here is an example:

class TRK {
class Fitting {
int x;
public:
Fitting(int x): x(x) {}
};

Fitting fitting;

public:
TRK(int y): fitting(y) {}
};

Having nested classes access the parent class

A nested class is just a regular class, only its name is nested. It does not automatically know where the non-static member variables of the parent are. A simple solution is to provide the nested class with a reference to the instance of the parent class, like so:

class TRK {
class Fitting {
TRK &parent;
int x;
public:
Fitting(TRK &parent, int x): parent(parent), x(x) {}

void foo() {
// Use something from the parent class
parent.bar();
}
};

Fitting fitting;

public:
TRK(int y): fitting(*this, y) {}
void bar() {}
};

Another option is to not store a reference to the parent in the child class, but rather to explicitly pass a reference to the parent to every member function of the child class:

class TRK {
class Fitting {
void foo(TRK &parent) {
// Use something from the parent class
parent.bar();
}
};

Fitting fitting;

public:
TRK(int y): fitting(y) {}
void bar() {}
void quux() {
fitting.bar(*this);
}
};

Calling a member function of the child class from the parent class is easy, as shown in TRK::quux().

If you want to use inheritance and have the base class be able to call functions in the derived class, then the curiously recurring template pattern can be used, like so:

template <typename Derived>
class TRK {
...

void bar() {}

void quux() {
// We need to static_cast<> ourself to get an object of type Derived
static_cast<Derived>(*this)::foo();
}
};

class Derived: TRK<Derived> {
...
void foo() {
// We can directly call any base class member functions here
bar();
}
}

Nested class member access on C++11

To close this question I'll take this as an answer:

"No, it's not treated as a member of the class, it's just scoped inside of it like anything else. You'll need an instance of Enclosing to access it's members."

  • this and several other comments addresses the problem in my code. Basically this is something that remains true for C++11.

Nested class in C#

Nested classes are usually used for small utility classes that have no use outside the enclosing (outer) class. For that reason, nested classes are usually private. (There's even an FxCop rule for that.)

Your code

In your case, the nested class BankAccountSection is not really useful, since it has no state by itself. CreatePersonalAccount might as well just be a method of the outer class.

Regarding static int accountNumber;: This will make accountNumber a shared field across all Bank objects, which defeats the whole purpose. Don't do that. If you really need to set a field of the Bank object inside the inner class, you need to pass a reference of the Bank object to the inner class. (This is different to Java, where such a reference is available automatically under some circumstances.) In your particular case, just get rid of the inner class.

Examples for legitimate use cases

  • You have a large algorithm inside a method. You realize that extracting this algorithm into its own class using many small methods and instance variables would increase readability. Since the algorithm is very specific and probably not useful for other classes, you put the algorithm into an inner class. Thus, you avoid cluttering your outer class with instance variables only used by that algorithm.
  • You create a List data structure, which is internally implemented as a linked list. Since you don't expose the list nodes to the outside world, you make the nodes an inner class.

Related:

  • Why/when should you use nested classes in .net? Or shouldn't you?

Why we use inner classes?

Some inner classes are exposed publicly (eg Map.Entry in Java) but that is by far the exception rather than the norm.

Inner classes are, basically, an implementation detail.

For example, Swing makes extensive use of inner classes for event listeners. Without them you would end up polluting the global namespace with a bunch of classes you otherwise don't need to see (which may make their purpose harder to determine).

Essentially inner classes are a form of scope. Package access hides classes from outside the package. Private inner classes hide that class from outside that class.

Inner classes in Java are also a substitute for a lack of function pointers or method delegates (which are in C#) or closures. They are the means of passing a function to another function. For example, in the Executor class you have:

void execute(Runnable r);

so you can pass a method in. In C/C++ that could be achieved with:

void execute(void (*run)());

being a pointer to a function.



Related Topics



Leave a reply



Submit