Benefit 1: The namespace aspect
Indeed, A
provides a namespace for B
, and this can help us structure our code much better. Consider a concrete example with vector
for A
, and iterator
for B
. Arguably,
class vector {
public:
class iterator { /*...*/ };
iterator begin() { /*...*/ }
};
is easier to type, to read, and to understand than
class vector_iterator {
/*...*/
};
class vector {
public:
vector_iterator begin() { /*...*/ }
};
Observe, in particular:
When the two classes (vector
and iterator
) depend on each other, i.e. use each other's members, the second version above would require one of the two to be forward-declared, and in some cases mutual type-dependencies might lead to unresolvable situations. (Using nested classes, it is much easier to avoid such problems, because within most parts of the nested class definition, the outer class is considered completely-defined. This is due to §9.2/2.)
You may very well have many other data types that maintain their own iterator
, e.g. linked_list
. Using the second version above, you'd need to define linked_list_iterator
as a separate class. Class names would get ever longer and complicated the more of these 'dependent' types and alternative types you added.
Benefit 2: Templates
Continuing the example above, consider now a function template that takes a container (such as vector
and linked_list
defined above) as arguments and iterates over them:
template <typename Container>
void iterate(const Container &container) {
/*...*/
}
Inside this function, you'd obviously very much like to use the iterator type of Container
. If that is a nested type, it's easy:
typename Container::iterator
But if it isn't, you would have to take the iterator type as a separate template parameter:
template <typename Container, typename Iterator>
void iterate(const Container &container) {
/*...*/
Iterator it = container.begin();
/*...*/
}
And if that iterator type does not appear among the function arguments, the compiler could not even guess the type. You'd have to explicitly add it in angle brackets each time you call the iterate
function.
Final notes: None of this has much to do with whether the nested class is declared as public or private. My examples above suggest a situation in which a public nested type is clearly preferrable, because I suppose the iterator
type should be able to be used outside the container class.