computer science II
c m s c 214  
f a l l   2 0 0 1  

Nested Classes

Background

The purpose of introducing nested classes in Project 2 is to create iterators that resemble (but are not identical) to the iterators in STL. In STL, this is how you would declare an iterator (that iteratates on a vector of int).
   vector<int>::iterator  pos;
The natural question to ask is: what is this crazy syntax for declaring an iterator?

Upon staring at the declaration more closely, you realize what kind of iterator pos is. It's an iterator for a vector of int values. Thus, this iterator can only be used to iterate on vector of int values. It can't be used to iterate on a vector of float values, or a vector of Foo values, or a vector of Foo pointers. Iterators are specific to a vector of a certain type.

Perhaps the crazy syntax was introduced when the STL was incorporated into Standard C++. After all, as long as namespaces and such are being added, why not change other things too? However, that's not a valid reason. A rule of thumb is not to create new syntax for a language unless there's some reasonable justification. In any case, STL existed and was implemented in C++ prior to being adopted into the Standard. So, it would suggest that this way of declaring iterators has been around for a while. And, so it has: it occurs with nested classes.

Nested Classes

In fact, iterators are implement in C++ as "nested classes". As you might guess, a nested class means a class declared inside another class. We will refer to the class on the "outside" as the outer class, and the class on the "inside" as the nested class.

You can declare a nested class:

For example,
class Outer {
   // PRIVATE nested class
   class PrivateNested {
       int data;
   public:
       PrivateNested & operator=( const PrivateNested & other );
   };

public:
   // PUBLIC nested class
   class PublicNested {
       int data;
   };
};
Of course, you can declare data members, member functions, etc. I haven't done so here.

Private Nested Classes

When you have a class declared in the "private" section of a class declaration, then only the "outer" class and other classes within the "outer" class can declare variables of that type.

For example, PrivateNested is a private nested class. Only Outer, PrivateNested and PublicNested can declare variables of type PrivateNested. If a method is not part of these classes, it can't declare a variable of type PrivateNested.

Public Nested Classes

On the other hand, a class declared in the public section can have variables declared of that that type, outside class methods. For example, in main(), you can declare:
int main()
{
   Outer::PublicNested  foo;
}
Here's where you see the unusual syntax, using the doublye colon. Since PublicNested is a nested class, then to fully indicate the correct type, you must list the outer class first, followed by two colon, then the nested (nested) class.

This allows other classes to have nested classes that are also called "PublicNested", without interfering with the "Outer::PublicNested" class. For example, there could be a "Foo::PublicNested" class. These would be two different classes.

In fact, you can have a class called PublicNested, which is not a nested class at all (despite it's name), and it will also not interfere with nested classes by the same name.

.h vs. cpp files

It's much easier for the compiler to determine that a class is a nested class in the class declaration (from the .h file). After all, you are declaring one class, nested inside the other.

However, the compiler can't really determine a class is nested in the definition of the classes (which appears in the .cpp file) without special syntax. Alas, C++ has rather kludgy syntax for nested classes.

For example, here's how you would write the code for three PrivateNested class methods: the default constructor, some arbitrary function, and operator=.

// default constructor
Outer::PrivateNested::PrivateNested()
{
  // code
}

// arbitrary function
void Outer::PrivateNested::foo()
{
  // code

}

// operator=
Outer::PrivateNested &
Outer::PrivateNested::operator=( const Outer::PrivateNested &other )
{
  // code
}
The operator= shows how vile the syntax can be. Whenever you want to refer to PrivateNested, you must precede it by Outer::. Why? Because there could be a non-nested class called PrivateNested.

In an example like this, it doesn't seem possible that this could be the case. Who would ever call a non-nested class PrivateNested? While that's true, it's very possible for a nested class to be called Node. And it's very possible for a non-nested class to be called Node, too. The language needs special syntax to differentiate between the two cases. Thus, only the non-nested class is properly called "Node", while the nested Node would have to be preceded by the outer class's name and two colons.

Why didn't you have to use such kludgy syntax in the .h file? If you're declaring a nested class within a .h file, the language assumes you will be referring to the nested class. It's far more likely that you will refer to the name of the class in a declaration (i.e., in a class header), then to some other non-nested class by the same name. (There's probably some other syntax, like ::PrivateNested, if you really need to to refer to a non-nested class by the same name).

Why nested classes?

The main reason to use nested classes is to avoid namespace collision. Suppose you're writing a singly linked list class, a doubly linked list class, and a binary search tree class. All such classes could have Node. Without nested classes, you'd have to call them SLLNode, DLLNode, and BSTNode, so the names wouldn't clash.

In C, this problem occurred all the time. You want to write a sort function on int arrays, float arrays, and Foo arrays. You'd have to name the functions different names in each case. In C++, functions can be overloaded, so it's no big deal. As long as two functions have different signatures (i.e., the number of parameters, the type of the parameters, and its constness), you can name them the same and the compiler can distinguish which is which.

The closest analogy is a nested class. Thus, having Node be a nested class of a singly linked list class, a doubly linked list class, and a binary search tree class ensures their names won't clash with one another.

Web Accessibility